From 078ba3c7134b4eb1ce338c660ab2e2c2d768c525 Mon Sep 17 00:00:00 2001 From: Mauve Date: Tue, 8 Sep 2026 15:12:29 +0800 Subject: [PATCH] init --- .gitignore | 8 + CRMMobileApi.iml | 10 + crm_mobile_runtime/appconfig.properties | 16 + .../convert/bin/BookingService$1.class | Bin 0 -> 7513 bytes .../convert/bin/BookingService.class | Bin 0 -> 135728 bytes .../import/import_other_booking.json | 197 + .../convert/bin/BookingService$1.class | Bin 0 -> 7513 bytes crm_runtime/convert/bin/BookingService.class | Bin 0 -> 135728 bytes docs/merge_daylight_dl_reservation_dedup.md | 101 + pom.xml | 253 + .../com/mgm/mcrm/CRMMobileApplication.java | 29 + src/main/java/com/mgm/mcrm/TestRun.java | 11 + .../HttpClientContextRequestFactory.java | 25 + .../controllers/SSOCallbackController.java | 39 + .../controllers/SSORestProcessController.java | 952 +++ .../mcrm/allotment/models/CfgAppChannel.java | 36 + .../models/CfgAppChannelDaylight.java | 30 + .../models/CfgAppChannelDaylightKey.java | 29 + .../allotment/models/CfgAppChannelKey.java | 46 + .../allotment/models/CfgOtherAllotment.java | 195 + .../models/CfgOtherAllotmentView.java | 331 + .../allotment/models/CfgOtherAppChannel.java | 76 + .../models/CfgOtherAppChannelKey.java | 50 + .../allotment/models/CfgRoomCriterias.java | 100 + .../models/CfgRoomCriteriasDaylight.java | 67 + .../models/CfgRoomCriteriasDaylightView.java | 113 + .../allotment/repositories/AppChannelDao.java | 13 + .../repositories/OtherAllotmentDao.java | 24 + .../repositories/OtherAllotmentViewDao.java | 28 + .../repositories/RoomCriteriaDao.java | 33 + .../repositories/RoomCriteriaDaylightDao.java | 56 + .../RoomCriteriaDaylightViewDao.java | 53 + .../controller/ApprovalController.java | 154 + .../approval/dtos/GetApproverRequest.java | 13 + .../approval/dtos/RejectApprovalResponse.java | 14 + .../approval/dtos/SubmitApprovalResponse.java | 17 + .../mcrm/approval/mappers/ApprovalMapper.java | 26 + .../mcrm/approval/models/ApprovalDetail.java | 57 + .../approval/models/ApprovalGamingData.java | 160 + .../approval/models/CfgApprovalRouting.java | 137 + .../approval/models/CfgRequestReason.java | 94 + .../repositories/ApprovalRoutingDao.java | 52 + .../repositories/RequestReasonDao.java | 37 + .../approval/service/ApprovalService.java | 1414 ++++ .../controllers/CfgSettingController.java | 102 + .../controllers/ConfigController.java | 158 + .../dtos/AvailableRoomQueryRequest.java | 18 + .../appsetting/dtos/BedTypeQueryRequest.java | 12 + .../dtos/CfgSettingQueryRequest.java | 8 + .../dtos/ExtendBookingQueryRequest.java | 20 + .../appsetting/dtos/PropertyQueryRequest.java | 14 + .../dtos/RoomCriteriaQueryRequest.java | 21 + .../dtos/RoomFeatureQueryRequest.java | 17 + .../appsetting/dtos/RoomQueryRequest.java | 14 + .../appsetting/dtos/RoomTypeQueryRequest.java | 11 + .../dtos/SysSettingQueryRequest.java | 12 + .../dtos/WaitlistBookingQueryRequest.java | 16 + .../mcrm/appsetting/models/CfgSettings.java | 33 + .../mcrm/appsetting/models/SysSetting.java | 42 + .../appsetting/repositories/SettingDao.java | 10 + .../repositories/SysSettingDao.java | 20 + .../appsetting/services/ConfigService.java | 719 ++ .../appsetting/services/SettingService.java | 28 + .../services/SysSettingService.java | 45 + .../controllers/MobileLoginController.java | 408 ++ .../dtos/AccountLoginRequest.java | 13 + .../dtos/AccountLoginResponse.java | 12 + .../mcrm/authorization/dtos/LoginInfo.java | 22 + .../authorization/dtos/LoginUserInfo.java | 12 + .../dtos/RefreshTokenResponse.java | 20 + .../authorization/dtos/SsoLoginRequest.java | 11 + .../authorization/dtos/SsoLoginResponse.java | 16 + .../authorization/dtos/UserLookupRequest.java | 9 + .../authorization/filters/JwtAuthFilter.java | 183 + .../mcrm/authorization/models/SysGroup.java | 43 + .../models/SysGroupDataPermission.java | 34 + .../models/SysGroupPermission.java | 28 + .../models/SysGroupPermissionKey.java | 38 + .../mcrm/authorization/models/SysRouter.java | 73 + .../models/SysRouterPermission.java | 31 + .../mcrm/authorization/models/SysUser.java | 50 + .../authorization/models/SysUserSetting.java | 37 + .../models/SysUserSettingKey.java | 40 + .../authorization/models/SysUserView.java | 57 + .../mgm/mcrm/authorization/models/Token.java | 37 + .../repositories/SysGroupDao.java | 23 + .../SysGroupDataPermissionDao.java | 22 + .../repositories/SysGroupPermissionDao.java | 20 + .../repositories/SysRouterDao.java | 22 + .../repositories/SysRouterPermissionDao.java | 31 + .../repositories/SysUserDao.java | 33 + .../repositories/SysUserSettingDao.java | 13 + .../repositories/SysUserViewDao.java | 25 + .../authorization/repositories/TokenDao.java | 37 + .../services/AuthorizationService.java | 165 + .../services/MgmUserService.java | 246 + .../services/SysGroupPermissionService.java | 90 + .../services/UserTokenService.java | 89 + .../authorization/utils/JwtTokenUtil.java | 142 + .../agebucket/models/SysAgebucket.java | 30 + .../repositories/SysAgebucketDao.java | 12 + .../agebucket/services/AgebucketService.java | 69 + .../daylight/dtos/ProfileDetail.java | 14 + .../daylight/dtos/ProfileMemberships.java | 19 + .../basesetting/daylight/dtos/VipCode.java | 15 + .../daylight/dtos/request/AmountLimit.java | 13 + .../dtos/request/CompRuleDateRange.java | 10 + .../dtos/request/ComplimentaryRuleLimits.java | 18 + .../dtos/request/CreateCompRuleRequest.java | 30 + .../dtos/request/UpdateCompRuleRequest.java | 13 + .../dtos/response/AccountResponse.java | 27 + .../dtos/response/AgebucketResponse.java | 16 + .../dtos/response/CancelReasonResponse.java | 13 + .../dtos/response/ProfileDetailResponse.java | 28 + .../response/RequestorApproverResponse.java | 17 + .../response/ReservationDoorKeyResponse.java | 11 + .../response/ReservationNoteResponse.java | 15 + .../response/ReservationQueueResponse.java | 11 + .../daylight/models/CfgBlockCodes.java | 53 + .../daylight/models/CfgCompPreset.java | 24 + .../models/CfgDaylightConfiguration.java | 32 + .../daylight/models/CfgDaylightMapping.java | 70 + .../daylight/models/CfgDaylightView.java | 156 + .../models/CfgExceptDaylightRoomTypes.java | 28 + .../daylight/models/CfgExceptionDaylight.java | 50 + .../CfgExceptionDaylightRoomTypesKey.java | 36 + .../models/CfgExceptionDaylightView.java | 150 + .../models/CfgExceptionOperaView.java | 136 + .../daylight/models/CfgItemInventory.java | 45 + .../daylight/models/CfgMarketCodes.java | 38 + .../models/CfgNonMGMStatusMapping.java | 121 + .../daylight/models/CfgOperaView.java | 145 + .../models/CfgOtherFollowUpStatus.java | 39 + .../daylight/models/CfgOtherSegment.java | 111 + .../daylight/models/CfgRateCodes.java | 37 + .../daylight/models/CfgSourceCodes.java | 35 + .../basesetting/daylight/models/CfgTiers.java | 40 + .../daylight/repositories/BlockCodeDao.java | 31 + .../daylight/repositories/CompPresetDao.java | 12 + .../DaylightConfigurationDao.java | 21 + .../daylight/repositories/DaylightDao.java | 27 + .../repositories/DaylightViewDao.java | 52 + .../repositories/ExceptionDaylightDao.java | 33 + .../ExceptionDaylightViewDao.java | 29 + .../repositories/ExceptionOperaDao.java | 35 + .../repositories/ExceptionOperaViewDao.java | 33 + .../repositories/ItemInventoryDao.java | 19 + .../daylight/repositories/MarketCodeDao.java | 35 + .../daylight/repositories/OperaViewDao.java | 36 + .../repositories/OtherSegmentDao.java | 21 + .../daylight/repositories/RateCodeDao.java | 35 + .../daylight/repositories/SourceCodeDao.java | 32 + .../daylight/repositories/TierDao.java | 19 + .../daylight/services/DaylightService.java | 2204 ++++++ .../response/DayLightProfileResponse.java | 11 + .../dtos/response/DescriptionResponse.java | 9 + .../dtos/response/ResultResponse.java | 36 + .../property/dtos/response/TokenResponse.java | 12 + .../property/models/CfgBlocks.java | 112 + .../property/models/CfgProperties.java | 47 + .../property/repositories/BlockDao.java | 35 + .../property/repositories/PropertyDao.java | 54 + .../property/services/PropertyCache.java | 31 + .../room/models/CfgBedTypeMapping.java | 46 + .../room/models/CfgBedTypeMappingView.java | 104 + .../room/models/CfgOtherRoomStatus.java | 100 + .../room/models/CfgRoomFeatures.java | 41 + .../basesetting/room/models/CfgRoomTypes.java | 39 + .../basesetting/room/models/CfgRooms.java | 67 + .../room/models/CfgRoomsRoomTypes.java | 53 + .../room/models/CfgRoomsRoomTypesKey.java | 46 + .../room/repositories/BedTypeMappingDao.java | 34 + .../room/repositories/OtherRoomStatusDao.java | 32 + .../room/repositories/RoomDao.java | 37 + .../room/repositories/RoomFeatureDao.java | 30 + .../room/repositories/RoomRoomTypeDao.java | 16 + .../room/repositories/RoomTypeDao.java | 33 + .../room/services/OtherRoomStatusService.java | 20 + .../basesetting/team/models/AppUsers.java | 144 + .../team/models/CfgDepartments.java | 68 + .../basesetting/team/models/CfgDivisions.java | 79 + .../team/models/CfgOtherUserMapping.java | 125 + .../basesetting/team/models/CfgSections.java | 68 + .../team/models/CfgTeamStructure.java | 85 + .../team/models/CfgTeamStructureView.java | 121 + .../team/repositories/AppUserDao.java | 30 + .../team/repositories/DepartmentDao.java | 34 + .../team/repositories/DivisionDao.java | 34 + .../repositories/OtherUserMappingDao.java | 21 + .../team/repositories/SectionDao.java | 32 + .../team/repositories/TeamStructureDao.java | 30 + .../repositories/TeamStructureViewDao.java | 36 + .../controllers/BookingController.java | 954 +++ .../controllers/WaitlistController.java | 86 + .../mcrm/booking/dtos/BookingCancelInfo.java | 15 + .../mcrm/booking/dtos/BookingDateEntry.java | 19 + .../com/mgm/mcrm/booking/dtos/BookingDto.java | 164 + .../mcrm/booking/dtos/BookingUserEntry.java | 9 + .../dtos/WebBatchUpdateWaitlistRequest.java | 10 + .../booking/dtos/daylight/AmountLock.java | 5 + .../mcrm/booking/dtos/daylight/Breakdown.java | 23 + .../dtos/daylight/GuestForBreakdown.java | 9 + .../requests/ChangeMiscChargeRequest.java | 11 + .../AccompanyingGuestDTO.java | 9 + .../createReservation/IndividualDTO.java | 121 + ...PurchaseElementsWithInventoryItemsDTO.java | 28 + .../createReservation/ReservationDTO.java | 110 + .../ReservationMembershipDTO.java | 14 + .../ReservationRequestDTO.java | 50 + .../DistributionChannelResponse.java | 11 + .../responses/GuaranteeTypeResponse.java | 11 + .../dtos/opera/CancelBookingIDPair.java | 34 + .../booking/dtos/opera/CancelBookingIDs.java | 20 + .../dtos/opera/CancelBookingRequest.java | 72 + .../dtos/opera/CancelBookingResponse.java | 35 + .../dtos/opera/CancelBookingResult.java | 55 + .../dtos/opera/CombineShareRequest.java | 89 + .../dtos/opera/CombineShareResponse.java | 31 + .../opera/CreateBookingHotelReservation.java | 41 + .../dtos/opera/CreateBookingProfile.java | 19 + .../dtos/opera/CreateBookingProfileIDs.java | 19 + .../dtos/opera/CreateBookingProfiles.java | 19 + .../dtos/opera/CreateBookingRequest.java | 263 + .../dtos/opera/CreateBookingResGuest.java | 19 + .../dtos/opera/CreateBookingResGuests.java | 19 + .../dtos/opera/CreateBookingResponse.java | 43 + .../dtos/opera/CreateBookingRoomStay.java | 33 + .../dtos/opera/CreateBookingRoomStays.java | 19 + .../dtos/opera/CreateBookingRoomType.java | 19 + .../CreateBookingRoomTypeDescription.java | 22 + .../dtos/opera/CreateBookingRoomTypes.java | 18 + .../dtos/opera/CreateBookingUniqueIDList.java | 22 + .../opera/FetchBookingAdditionalDetail.java | 23 + ...tchBookingAdditionalDetailDescription.java | 21 + .../opera/FetchBookingAdditionalDetails.java | 22 + .../dtos/opera/FetchBookingAddresses.java | 18 + .../dtos/opera/FetchBookingAllowance.java | 45 + .../opera/FetchBookingAllowanceConvert.java | 39 + .../dtos/opera/FetchBookingAmount.java | 44 + .../dtos/opera/FetchBookingAmountConvert.java | 39 + .../opera/FetchBookingArrivalTransport.java | 62 + .../booking/dtos/opera/FetchBookingBase.java | 46 + .../dtos/opera/FetchBookingBaseConvert.java | 39 + .../dtos/opera/FetchBookingCancelTerm.java | 50 + .../dtos/opera/FetchBookingCharges.java | 59 + .../FetchBookingChargesForPostingDate.java | 44 + .../dtos/opera/FetchBookingComment.java | 21 + .../dtos/opera/FetchBookingComments.java | 22 + .../dtos/opera/FetchBookingCompany.java | 46 + .../opera/FetchBookingCurrentBalance.java | 45 + .../FetchBookingCurrentBalanceConvert.java | 39 + .../dtos/opera/FetchBookingCustomer.java | 19 + .../opera/FetchBookingDepartureTransport.java | 62 + .../dtos/opera/FetchBookingDepositAmount.java | 44 + .../FetchBookingDepositAmountConvert.java | 39 + .../opera/FetchBookingDepositDueAmount.java | 44 + .../FetchBookingDepositDueAmountConvert.java | 39 + .../opera/FetchBookingDepositRequired.java | 31 + .../dtos/opera/FetchBookingDescription.java | 20 + .../opera/FetchBookingExpectedCharges.java | 72 + .../dtos/opera/FetchBookingGuarantee.java | 26 + .../dtos/opera/FetchBookingGuestCount.java | 37 + .../dtos/opera/FetchBookingGuestCounts.java | 22 + .../opera/FetchBookingHotelReference.java | 46 + .../FetchBookingHotelReferenceConvert.java | 39 + .../opera/FetchBookingHotelReservation.java | 401 ++ .../dtos/opera/FetchBookingMemberships.java | 20 + .../dtos/opera/FetchBookingNameAddress.java | 33 + .../opera/FetchBookingNameMembership.java | 104 + .../dtos/opera/FetchBookingNamePhone.java | 22 + .../dtos/opera/FetchBookingOtherPayment.java | 25 + .../dtos/opera/FetchBookingPackage.java | 101 + .../dtos/opera/FetchBookingPackageAmount.java | 45 + .../FetchBookingPackageAmountConvert.java | 39 + .../dtos/opera/FetchBookingPackages.java | 21 + .../dtos/opera/FetchBookingPayment.java | 21 + .../dtos/opera/FetchBookingPaymentType.java | 21 + .../opera/FetchBookingPaymentsAccepted.java | 21 + .../dtos/opera/FetchBookingPersonName.java | 45 + .../dtos/opera/FetchBookingPhones.java | 23 + .../dtos/opera/FetchBookingProfile.java | 75 + .../dtos/opera/FetchBookingProfileIDs.java | 22 + .../dtos/opera/FetchBookingProfiles.java | 23 + .../booking/dtos/opera/FetchBookingRate.java | 19 + .../dtos/opera/FetchBookingRatePlan.java | 89 + .../FetchBookingRatePlanDescription.java | 21 + .../dtos/opera/FetchBookingRatePlans.java | 21 + .../booking/dtos/opera/FetchBookingRates.java | 21 + .../dtos/opera/FetchBookingRequest.java | 66 + .../dtos/opera/FetchBookingResGuest.java | 67 + .../dtos/opera/FetchBookingResGuestRPH.java | 26 + .../dtos/opera/FetchBookingResGuestRPHs.java | 20 + .../dtos/opera/FetchBookingResGuests.java | 19 + .../FetchBookingReservationGuarantee.java | 38 + .../opera/FetchBookingReservationHistory.java | 62 + .../FetchBookingReservationPaymentInfo.java | 37 + .../FetchBookingReservationPayments.java | 23 + .../dtos/opera/FetchBookingResponse.java | 45 + .../dtos/opera/FetchBookingResult.java | 44 + .../dtos/opera/FetchBookingRoomRate.java | 56 + .../FetchBookingRoomRateAndPackages.java | 49 + .../dtos/opera/FetchBookingRoomRates.java | 24 + .../dtos/opera/FetchBookingRoomStay.java | 174 + .../dtos/opera/FetchBookingRoomStays.java | 19 + .../FetchBookingRoomToChargeDescription.java | 21 + ...chBookingRoomToChargeShortDescription.java | 21 + .../dtos/opera/FetchBookingRoomType.java | 113 + .../FetchBookingRoomTypeDescription.java | 21 + .../FetchBookingRoomTypeShortDescription.java | 21 + .../dtos/opera/FetchBookingRoomTypes.java | 19 + .../FetchBookingShareReservationDetails.java | 55 + .../opera/FetchBookingShareReservations.java | 24 + .../opera/FetchBookingShortDescription.java | 20 + .../dtos/opera/FetchBookingTaxAmount.java | 45 + .../opera/FetchBookingTaxAmountConvert.java | 39 + .../dtos/opera/FetchBookingTaxesAndFees.java | 49 + .../booking/dtos/opera/FetchBookingText.java | 17 + .../dtos/opera/FetchBookingTimeSpan.java | 34 + .../booking/dtos/opera/FetchBookingTotal.java | 45 + .../dtos/opera/FetchBookingTotalConvert.java | 39 + .../dtos/opera/FetchBookingUniqueID.java | 44 + .../opera/FetchBookingUniqueIDConvert.java | 39 + .../dtos/opera/FetchBookingUniqueIDList.java | 22 + .../opera/FetchBookingUserDefinedValue.java | 48 + .../opera/FetchBookingUserDefinedValues.java | 24 + .../dtos/opera/FutureBookingSummaryBase.java | 46 + .../FutureBookingSummaryBaseConvert.java | 39 + .../dtos/opera/FutureBookingSummaryRate.java | 21 + .../dtos/opera/GuestRequestsRequest.java | 166 + .../dtos/opera/GuestRequestsResponse.java | 35 + .../dtos/opera/GuestRequestsResult.java | 44 + .../dtos/opera/InsertGuestCardRequest.java | 84 + .../dtos/opera/InsertGuestCardResponse.java | 35 + .../dtos/opera/ModifyBookingRequest.java | 182 + .../dtos/opera/ModifyBookingResponse.java | 12 + .../dtos/opera/UpdatePassportRequest.java | 69 + .../dtos/opera/UpdatePassportResponse.java | 35 + .../booking/dtos/opera/schema/Comment.java | 41 + .../dtos/opera/schema/ConfirmationNumber.java | 32 + .../dtos/opera/schema/GuestRequest.java | 52 + .../dtos/opera/schema/GuestRequestMsg.java | 82 + .../dtos/opera/schema/HotelReference.java | 28 + .../booking/dtos/opera/schema/OGHeader.java | 44 + .../dtos/opera/schema/SpecialRequest.java | 21 + .../mcrm/booking/dtos/opera/schema/Trace.java | 42 + .../dtos/search/BookingQueryRequest.java | 29 + .../dtos/search/BookingSearchRequest.java | 11 + .../dtos/search/CheckSecondTPDRequest.java | 15 + .../booking/dtos/search/CheckTPDRequest.java | 14 + .../mcrm/booking/dtos/search/DateRange.java | 17 + .../dtos/search/GetBookingByGroupRequest.java | 8 + .../dtos/search/GetBookingByIdRequest.java | 8 + .../search/GetBookingByNameIdRequest.java | 14 + .../dtos/search/GetOperaBookingRequest.java | 8 + .../dtos/search/PlayerLookupRequest.java | 8 + .../dtos/search/WebRecordSearchRequest.java | 12 + .../mcrm/booking/enums/ProfileTierEnums.java | 45 + .../mcrm/booking/mappers/BookingMapper.java | 89 + .../com/mgm/mcrm/booking/models/Bookings.java | 222 + .../mgm/mcrm/booking/models/BookingsView.java | 283 + .../mcrm/booking/models/CfgBookingTypes.java | 80 + .../mgm/mcrm/booking/models/GamingData.java | 212 + .../mcrm/booking/models/NonMGMBookings.java | 155 + .../mcrm/booking/models/OWSTransactions.java | 63 + .../mgm/mcrm/booking/models/OperaComment.java | 29 + .../mcrm/booking/models/OperaDBBooking.java | 246 + .../mgm/mcrm/booking/models/OperaDBRate.java | 124 + .../mcrm/booking/repositories/BookingDao.java | 96 + .../booking/repositories/BookingTypeDao.java | 22 + .../booking/repositories/BookingViewDao.java | 136 + .../booking/repositories/GamingDataDao.java | 15 + .../repositories/NonMGMBookingDao.java | 23 + .../repositories/NonMGMStatusMappingDao.java | 19 + .../OWSTransactionsRepository.java | 14 + .../repositories/OtherAppChannelDao.java | 14 + .../repositories/OtherFollowUpStatusDao.java | 15 + .../mcrm/booking/services/BookingService.java | 6111 +++++++++++++++++ .../services/NonMGMBookingService.java | 955 +++ .../services/OWSTransactionsService.java | 24 + .../services/OperaDBBookingService.java | 221 + .../mcrm/booking/services/OperaService.java | 1242 ++++ .../services/WaitlistBookingService.java | 709 ++ .../services/mockup/BookingServiceMockup.java | 185 + .../annotation/logging/OperationLog.java | 13 + .../annotation/security/AccessToken.java | 11 + .../common/annotation/security/PassToken.java | 11 + .../mcrm/common/config/DataSourceConfig.java | 32 + .../mcrm/common/config/HttpClientConfig.java | 118 + .../mgm/mcrm/common/config/HttpHeader.java | 26 + .../com/mgm/mcrm/common/config/JMSConfig.java | 74 + .../common/config/MGMDataSourceConfig.java | 74 + .../common/config/OperaDataSourceConfig.java | 69 + .../mgm/mcrm/common/config/SwaggerConfig.java | 18 + .../mcrm/common/config/WebFilterConfig.java | 88 + .../mgm/mcrm/common/constants/SysCommon.java | 690 ++ .../mcrm/common/constants/SysConstants.java | 30 + .../mgm/mcrm/common/dtos/BaseApiResponse.java | 264 + .../mcrm/common/dtos/BaseQueryRequest.java | 53 + .../com/mgm/mcrm/common/dtos/CachedToken.java | 21 + .../mgm/mcrm/common/dtos/DataTableResult.java | 13 + .../mcrm/common/dtos/EumnApprovalStatus.java | 66 + .../com/mgm/mcrm/common/dtos/HttpResult.java | 69 + .../mcrm/common/dtos/RequestDefination.java | 21 + .../mcrm/common/dtos/config/APIConfig.java | 276 + .../dtos/data_import/ValidateResult.java | 49 + .../booking/OtherBookingImportRow.java | 38 + .../dtos/excel_export/ColumnDefine.java | 34 + .../common/dtos/excel_export/DataElement.java | 85 + .../dtos/excel_export/ExportDefination.java | 24 + .../common/dtos/excel_export/ExportSheet.java | 26 + .../common/dtos/excel_model/ColumnDefine.java | 99 + .../dtos/excel_model/ColumnGroupInfo.java | 57 + .../common/dtos/excel_model/DataBlock.java | 100 + .../common/dtos/excel_model/ExportDefine.java | 34 + .../common/dtos/excel_model/GroupItem.java | 27 + .../common/dtos/excel_model/ImportDefine.java | 34 + .../common/dtos/excel_model/RowFieldInfo.java | 73 + .../common/dtos/excel_model/SheetDefine.java | 30 + .../dtos/http_util/HttpRequestDefine.java | 100 + .../dtos/http_util/HttpResponseResult.java | 83 + .../mgm_api/ApprovalGamingDataResult.java | 39 + .../common/dtos/mgm_api/ApproverRecord.java | 25 + .../dtos/mgm_api/ApproverRecordResult.java | 102 + .../common/dtos/mgm_api/ApproverResult.java | 37 + .../dtos/mgm_api/CheckApproverResult.java | 17 + .../mcrm/common/dtos/mgm_api/ItemRecord.java | 23 + .../dtos/mgm_api/NonMGMBookingApiResult.java | 33 + .../dtos/mgm_api/NonMGMBookingRecord.java | 55 + .../dtos/mgm_api/PlayerProfileEntry.java | 32 + .../dtos/mgm_api/PlayerTPDApiResult.java | 66 + .../dtos/mgm_api/TodoDashboardRecord.java | 86 + .../dtos/mgm_api/TodoDashboardResult.java | 21 + .../dtos/mgm_api/TodoDateListRecord.java | 40 + .../dtos/mgm_api/TodoDateListResult.java | 42 + .../dtos/mgm_api/TodoDetailDescription.java | 42 + .../common/dtos/mgm_api/TodoDetailResult.java | 63 + .../common/dtos/mgm_api/TodoListRecord.java | 236 + .../common/dtos/mgm_api/TodoListResult.java | 43 + .../dtos/mgm_api/UserInfoApiRecord.java | 37 + .../dtos/mgm_api/UserInfoApiResult.java | 31 + .../mgm_api/WaitlistBookingApiResult.java | 33 + .../dtos/mgm_api/WaitlistBookingRecord.java | 29 + .../dtos/mgm_api/WaitlistDataApiResult.java | 33 + .../dtos/mgm_api/WaitlistDataRecord.java | 153 + .../common/dtos/msg/AppSettingMsgData.java | 20 + .../mcrm/common/dtos/msg/JMSTextMessage.java | 27 + .../mcrm/common/dtos/msg/UpdateCfgItem.java | 18 + .../common/dtos/system/AppServerState.java | 56 + .../common/dtos/system/ResFileResult.java | 34 + .../mcrm/common/dtos/system/RouterPages.java | 22 + .../common/enums/DeliveryReceiptState.java | 56 + .../mcrm/common/enums/EnumBookingStatus.java | 78 + .../mgm/mcrm/common/enums/HttpMethods.java | 74 + .../common/filters/ConfigHeaderFilter.java | 76 + .../common/httpclient/HttpClientExecutor.java | 523 ++ .../common/httpclient/HttpCookieContext.java | 46 + .../common/httpclient/HttpEntityBuilder.java | 310 + .../common/httpclient/HttpHeaderBuilder.java | 697 ++ .../httpclient/HttpParameterBuilder.java | 72 + .../common/httpclient/HttpRequestOptions.java | 375 + .../common/httpclient/HttpSslSupport.java | 197 + .../interceptor/ControllerLogAspector.java | 117 + .../common/jms/AppControlMsgConsumer.java | 58 + .../mcrm/common/jms/AppControlMsgSender.java | 47 + .../common/jms/BookingControlMsgConsumer.java | 97 + .../common/jms/BookingControlMsgSender.java | 51 + .../mcrm/common/listener/ConfigListener.java | 60 + .../common/schedule/AppSystemScheduleJob.java | 27 + .../common/schedule/BookingScheduleJob.java | 109 + .../mgm/mcrm/common/services/HttpService.java | 210 + .../common/services/HttpTokenService.java.bak | 573 ++ .../mcrm/common/services/MGMApiService.java | 419 ++ .../services/SysServerStateService.java | 30 + .../com/mgm/mcrm/common/utils/ADFSUtil.java | 185 + .../com/mgm/mcrm/common/utils/AESUtil.java | 155 + .../com/mgm/mcrm/common/utils/DaoUtil.java | 86 + .../mgm/mcrm/common/utils/DateTimeUtil.java | 292 + .../com/mgm/mcrm/common/utils/ETLXstream.java | 24 + .../mgm/mcrm/common/utils/EncryptUtil.java | 31 + .../com/mgm/mcrm/common/utils/ExcelUtils.java | 931 +++ .../com/mgm/mcrm/common/utils/HttpUtil.java | 264 + .../com/mgm/mcrm/common/utils/LogUtil.java | 85 + .../com/mgm/mcrm/common/utils/MailConfig.java | 88 + .../utils/MessageReceiverListenerImpl.java | 54 + .../mgm/mcrm/common/utils/NetworkUtil.java | 378 + .../com/mgm/mcrm/common/utils/PDFUtil.java | 102 + .../com/mgm/mcrm/common/utils/SOAPUtil.java | 337 + .../com/mgm/mcrm/common/utils/SendEmail.java | 956 +++ .../mgm/mcrm/common/utils/XMLBuliderUtil.java | 35 + .../common/utils/mockup/AjaxResultMockup.java | 72 + .../common/utils/mockup/HttpUtilMockup.java | 264 + .../controllers/SysLogAppController.java | 65 + .../controllers/SysLogConfirmController.java | 38 + .../SysLogDeviceTokenController.java | 32 + .../com/mgm/mcrm/logging/dtos/AppLogDto.java | 15 + .../logging/dtos/MobileConfirmLogRequest.java | 9 + .../dtos/request/SaveDeviceTokenRequest.java | 11 + .../request/UpdateDeviceTokenRequest.java | 10 + .../response/SaveDeviceTokenResponse.java | 9 + .../response/UpdateDeviceTokenResponse.java | 9 + .../mgm/mcrm/logging/models/SysLogApp.java | 114 + .../mcrm/logging/models/SysLogBooking.java | 101 + .../logging/models/SysLogDeviceToken.java | 39 + .../mgm/mcrm/logging/models/SysLogETA.java | 91 + .../mgm/mcrm/logging/models/SysLogLogin.java | 115 + .../mcrm/logging/models/SysLogLoginIp.java | 94 + .../logging/models/SysLogMobileConfirm.java | 52 + .../mcrm/logging/models/SysLogOperation.java | 115 + .../logging/repositories/SysLogAppDao.java | 30 + .../repositories/SysLogBookingDao.java | 22 + .../repositories/SysLogConfirmDao.java | 20 + .../repositories/SysLogDeviceTokenDao.java | 13 + .../logging/repositories/SysLogETADao.java | 10 + .../logging/repositories/SysLogLoginDao.java | 19 + .../repositories/SysLogLoginIpDao.java | 28 + .../repositories/SysLogOperationDao.java | 19 + .../logging/services/SysLogAppService.java | 18 + .../services/SysLogBookingService.java | 95 + .../services/SysLogConfirmService.java | 38 + .../services/SysLogDeviceTokenService.java | 74 + .../logging/services/SysLogETAService.java | 18 + .../services/SysLogLoginIpService.java | 56 + .../logging/services/SysLogLoginService.java | 19 + .../services/SysLogOperationService.java | 18 + .../notification/config/ApnClientConfig.java | 109 + .../controllers/EmailTemplateController.java | 44 + .../controllers/NotificationController.java | 101 + .../ChangeNotificationStatusRequest.java | 8 + .../request/GenerateBookingEmailRequest.java | 10 + .../dtos/request/SendNotificationRequest.java | 30 + .../ChangeNotificationStatusResponse.java | 18 + .../CountNotificationByUserIdResponse.java | 10 + .../response/GetNotificationResponse.java | 14 + .../notification/models/CfgEmailTemplate.java | 182 + .../mgm/mcrm/notification/models/Email.java | 110 + .../models/SysLogNotification.java | 68 + .../notification/repositories/EmailDao.java | 11 + .../repositories/EmailTemplateDao.java | 14 + .../SysLogNotificationRepository.java | 14 + .../services/ApnNotificationService.java | 140 + .../services/EmailTemplateService.java | 342 + .../services/NotificationService.java | 201 + .../player/controllers/PlayerController.java | 200 + .../player/controllers/TodoController.java | 270 + .../mgm/mcrm/player/dtos/BasePricePerDay.java | 11 + .../player/dtos/CancellationReasonResult.java | 14 + .../mgm/mcrm/player/dtos/PlayerProfile.java | 75 + .../com/mgm/mcrm/player/dtos/PlayerTPD.java | 51 + .../mcrm/player/dtos/ProjectedRevenue.java | 9 + .../player/dtos/ProjectedRevenueAmount.java | 12 + .../mcrm/player/dtos/RatePricingDetail.java | 11 + .../com/mgm/mcrm/player/dtos/StatusCode.java | 9 + .../com/mgm/mcrm/player/dtos/UserInfo.java | 136 + .../player/dtos/request/EtaRecordInfo.java | 9 + .../dtos/request/GetDashboardRequest.java | 8 + .../dtos/request/GetTodoDetailRequest.java | 21 + .../dtos/request/GetTodoListRequest.java | 20 + .../request/TodoCancelBookingRequest.java | 19 + .../dtos/request/TodoChangeDateRequest.java | 25 + .../dtos/request/TodoSubmitETARequest.java | 16 + .../request/WebCheckPlayerTPDRequest.java | 16 + .../dtos/request/WebPlayerLookupRequest.java | 9 + .../response/CancelReasonResultResponse.java | 33 + .../response/DaylightReservationResponse.java | 51 + .../dtos/response/GetDashboardResponse.java | 12 + .../dtos/response/GetTodoDetailResponse.java | 13 + .../dtos/response/GetTodoListResponse.java | 4 + .../response/ReservationResultResponse.java | 32 + .../mcrm/player/services/PlayerService.java | 400 ++ .../mgm/mcrm/player/services/TodoService.java | 989 +++ .../AuthKey_79FNU7K4J9_Development.p8 | 6 + src/main/resources/application-dev.yml | 161 + src/main/resources/application-dev2.yml | 131 + src/main/resources/application.yml | 3 + src/main/resources/i18n/messages.properties | 0 .../resources/i18n/messages_en_US.properties | 26 + .../resources/i18n/messages_zh_CN.properties | 26 + .../resources/i18n/messages_zh_TW.properties | 26 + src/main/resources/idp-metadata.xml | 1 + src/main/resources/logback.xml | 60 + src/main/resources/mcrm.willtechmacau.com.pfx | Bin 0 -> 4653 bytes src/main/resources/mockup/app/getBlock.json | 20 + .../mockup/app/getBookingsByNameId.json | 283 + .../resources/mockup/app/getCriteria.json | 68 + .../resources/mockup/app/getProperty.json | 37 + src/main/resources/mockup/app/getRoom.json | 53 + .../resources/mockup/app/getRoomType.json | 68 + src/main/resources/mockup/app/getSpecial.json | 28 + .../mockup/app/getTodoDashboard_1.json | 76 + .../mockup/app/getTodoDashboard_2.json | 87 + .../mockup/app/getTodoDashboard_3.json | 66 + .../mockup/app/getTodoDashboard_4.json | 85 + .../resources/mockup/app/getTodoDetail_1.json | 67 + .../resources/mockup/app/getTodoDetail_2.json | 63 + .../resources/mockup/app/getTodoDetail_3.json | 68 + .../resources/mockup/app/getTodoDetail_4.json | 64 + .../resources/mockup/app/getTodoList_1.json | 216 + .../resources/mockup/app/getTodoList_2.json | 58 + .../resources/mockup/app/getTodoList_3.json | 34 + .../resources/mockup/app/getTodoList_4.json | 86 + .../resources/mockup/app/getTodoList_5.json | 84 + .../resources/mockup/app/getTodoList_6.json | 83 + .../resources/mockup/app/getTodoList_7.json | 58 + .../resources/mockup/app/getTodoList_8.json | 87 + .../resources/mockup/app/getTodoList_9.json | 84 + .../resources/mockup/app/playerProfile.json | 11 + src/main/resources/mockup/app/submitETA.json | 4 + .../mockup/approval/getApprovalData.json | 75 + .../mockup/approval/getApprover.json | 17 + .../http/check_player_tpd_all_pass.json | 18 + .../http/check_player_tpd_not_all_pass.json | 18 + .../http/check_player_tpd_partly_pass.json | 18 + .../http/get_player_profile_api_res1.json | 19 + .../http/get_player_profile_api_res10.json | 19 + .../http/get_player_profile_api_res11.json | 19 + .../http/get_player_profile_api_res12.json | 19 + .../http/get_player_profile_api_res13.json | 19 + .../http/get_player_profile_api_res14.json | 19 + .../http/get_player_profile_api_res15.json | 19 + .../http/get_player_profile_api_res16.json | 19 + .../http/get_player_profile_api_res17.json | 19 + .../http/get_player_profile_api_res18.json | 19 + .../http/get_player_profile_api_res19.json | 19 + .../http/get_player_profile_api_res2.json | 19 + .../http/get_player_profile_api_res20.json | 19 + .../http/get_player_profile_api_res21.json | 19 + .../http/get_player_profile_api_res22.json | 19 + .../http/get_player_profile_api_res23.json | 19 + .../http/get_player_profile_api_res24.json | 19 + .../http/get_player_profile_api_res25.json | 19 + .../http/get_player_profile_api_res26.json | 19 + .../http/get_player_profile_api_res27.json | 19 + .../http/get_player_profile_api_res28.json | 19 + .../http/get_player_profile_api_res29.json | 19 + .../http/get_player_profile_api_res3.json | 19 + .../http/get_player_profile_api_res30.json | 19 + .../http/get_player_profile_api_res31.json | 19 + .../http/get_player_profile_api_res4.json | 19 + .../http/get_player_profile_api_res5.json | 19 + .../http/get_player_profile_api_res6.json | 19 + .../http/get_player_profile_api_res7.json | 19 + .../http/get_player_profile_api_res8.json | 19 + .../http/get_player_profile_api_res9.json | 19 + .../mockup/http/get_user_info_api_res1.json | 16 + .../mockup/http/get_user_info_api_res10.json | 16 + .../mockup/http/get_user_info_api_res11.json | 16 + .../mockup/http/get_user_info_api_res12.json | 16 + .../mockup/http/get_user_info_api_res13.json | 16 + .../mockup/http/get_user_info_api_res14.json | 16 + .../mockup/http/get_user_info_api_res15.json | 16 + .../mockup/http/get_user_info_api_res16.json | 16 + .../mockup/http/get_user_info_api_res17.json | 16 + .../mockup/http/get_user_info_api_res2.json | 16 + .../mockup/http/get_user_info_api_res3.json | 16 + .../mockup/http/get_user_info_api_res4.json | 16 + .../mockup/http/get_user_info_api_res5.json | 16 + .../mockup/http/get_user_info_api_res6.json | 16 + .../mockup/http/get_user_info_api_res7.json | 16 + .../mockup/http/get_user_info_api_res8.json | 16 + .../mockup/http/get_user_info_api_res9.json | 16 + .../http/non_mgm_booking_no_record.json | 6 + .../http/non_mgm_booking_with_record.json | 24 + .../resources/mockup/mgm_api_mockup_def.json | 596 ++ src/main/resources/mockup/system/login.json | 16 + src/main/resources/static/WM.png | Bin 0 -> 8468 bytes src/main/resources/static/WP.png | Bin 0 -> 10052 bytes src/main/resources/static/logon1.png | Bin 0 -> 38970 bytes src/main/resources/templates/mfalogin.shtml | 22 + .../mgm/daylight/EnumBookingStatusTest.java | 21 + .../mgm/daylight/HttpEntityBuilderTest.java | 29 + src/test/java/com/mgm/daylight/SmallTest.java | 19 + .../BookingControllerRecordSearchTest.java | 76 + 672 files changed, 56677 insertions(+) create mode 100644 .gitignore create mode 100644 CRMMobileApi.iml create mode 100644 crm_mobile_runtime/appconfig.properties create mode 100644 crm_mobile_runtime/convert/bin/BookingService$1.class create mode 100644 crm_mobile_runtime/convert/bin/BookingService.class create mode 100644 crm_mobile_runtime/excel_define/import/import_other_booking.json create mode 100644 crm_runtime/convert/bin/BookingService$1.class create mode 100644 crm_runtime/convert/bin/BookingService.class create mode 100644 docs/merge_daylight_dl_reservation_dedup.md create mode 100644 pom.xml create mode 100644 src/main/java/com/mgm/mcrm/CRMMobileApplication.java create mode 100644 src/main/java/com/mgm/mcrm/TestRun.java create mode 100644 src/main/java/com/mgm/mcrm/adfs/config/HttpClientContextRequestFactory.java create mode 100644 src/main/java/com/mgm/mcrm/adfs/controllers/SSOCallbackController.java create mode 100644 src/main/java/com/mgm/mcrm/adfs/controllers/SSORestProcessController.java create mode 100644 src/main/java/com/mgm/mcrm/allotment/models/CfgAppChannel.java create mode 100644 src/main/java/com/mgm/mcrm/allotment/models/CfgAppChannelDaylight.java create mode 100644 src/main/java/com/mgm/mcrm/allotment/models/CfgAppChannelDaylightKey.java create mode 100644 src/main/java/com/mgm/mcrm/allotment/models/CfgAppChannelKey.java create mode 100644 src/main/java/com/mgm/mcrm/allotment/models/CfgOtherAllotment.java create mode 100644 src/main/java/com/mgm/mcrm/allotment/models/CfgOtherAllotmentView.java create mode 100644 src/main/java/com/mgm/mcrm/allotment/models/CfgOtherAppChannel.java create mode 100644 src/main/java/com/mgm/mcrm/allotment/models/CfgOtherAppChannelKey.java create mode 100644 src/main/java/com/mgm/mcrm/allotment/models/CfgRoomCriterias.java create mode 100644 src/main/java/com/mgm/mcrm/allotment/models/CfgRoomCriteriasDaylight.java create mode 100644 src/main/java/com/mgm/mcrm/allotment/models/CfgRoomCriteriasDaylightView.java create mode 100644 src/main/java/com/mgm/mcrm/allotment/repositories/AppChannelDao.java create mode 100644 src/main/java/com/mgm/mcrm/allotment/repositories/OtherAllotmentDao.java create mode 100644 src/main/java/com/mgm/mcrm/allotment/repositories/OtherAllotmentViewDao.java create mode 100644 src/main/java/com/mgm/mcrm/allotment/repositories/RoomCriteriaDao.java create mode 100644 src/main/java/com/mgm/mcrm/allotment/repositories/RoomCriteriaDaylightDao.java create mode 100644 src/main/java/com/mgm/mcrm/allotment/repositories/RoomCriteriaDaylightViewDao.java create mode 100644 src/main/java/com/mgm/mcrm/approval/controller/ApprovalController.java create mode 100644 src/main/java/com/mgm/mcrm/approval/dtos/GetApproverRequest.java create mode 100644 src/main/java/com/mgm/mcrm/approval/dtos/RejectApprovalResponse.java create mode 100644 src/main/java/com/mgm/mcrm/approval/dtos/SubmitApprovalResponse.java create mode 100644 src/main/java/com/mgm/mcrm/approval/mappers/ApprovalMapper.java create mode 100644 src/main/java/com/mgm/mcrm/approval/models/ApprovalDetail.java create mode 100644 src/main/java/com/mgm/mcrm/approval/models/ApprovalGamingData.java create mode 100644 src/main/java/com/mgm/mcrm/approval/models/CfgApprovalRouting.java create mode 100644 src/main/java/com/mgm/mcrm/approval/models/CfgRequestReason.java create mode 100644 src/main/java/com/mgm/mcrm/approval/repositories/ApprovalRoutingDao.java create mode 100644 src/main/java/com/mgm/mcrm/approval/repositories/RequestReasonDao.java create mode 100644 src/main/java/com/mgm/mcrm/approval/service/ApprovalService.java create mode 100644 src/main/java/com/mgm/mcrm/appsetting/controllers/CfgSettingController.java create mode 100644 src/main/java/com/mgm/mcrm/appsetting/controllers/ConfigController.java create mode 100644 src/main/java/com/mgm/mcrm/appsetting/dtos/AvailableRoomQueryRequest.java create mode 100644 src/main/java/com/mgm/mcrm/appsetting/dtos/BedTypeQueryRequest.java create mode 100644 src/main/java/com/mgm/mcrm/appsetting/dtos/CfgSettingQueryRequest.java create mode 100644 src/main/java/com/mgm/mcrm/appsetting/dtos/ExtendBookingQueryRequest.java create mode 100644 src/main/java/com/mgm/mcrm/appsetting/dtos/PropertyQueryRequest.java create mode 100644 src/main/java/com/mgm/mcrm/appsetting/dtos/RoomCriteriaQueryRequest.java create mode 100644 src/main/java/com/mgm/mcrm/appsetting/dtos/RoomFeatureQueryRequest.java create mode 100644 src/main/java/com/mgm/mcrm/appsetting/dtos/RoomQueryRequest.java create mode 100644 src/main/java/com/mgm/mcrm/appsetting/dtos/RoomTypeQueryRequest.java create mode 100644 src/main/java/com/mgm/mcrm/appsetting/dtos/SysSettingQueryRequest.java create mode 100644 src/main/java/com/mgm/mcrm/appsetting/dtos/WaitlistBookingQueryRequest.java create mode 100644 src/main/java/com/mgm/mcrm/appsetting/models/CfgSettings.java create mode 100644 src/main/java/com/mgm/mcrm/appsetting/models/SysSetting.java create mode 100644 src/main/java/com/mgm/mcrm/appsetting/repositories/SettingDao.java create mode 100644 src/main/java/com/mgm/mcrm/appsetting/repositories/SysSettingDao.java create mode 100644 src/main/java/com/mgm/mcrm/appsetting/services/ConfigService.java create mode 100644 src/main/java/com/mgm/mcrm/appsetting/services/SettingService.java create mode 100644 src/main/java/com/mgm/mcrm/appsetting/services/SysSettingService.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/controllers/MobileLoginController.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/dtos/AccountLoginRequest.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/dtos/AccountLoginResponse.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/dtos/LoginInfo.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/dtos/LoginUserInfo.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/dtos/RefreshTokenResponse.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/dtos/SsoLoginRequest.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/dtos/SsoLoginResponse.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/dtos/UserLookupRequest.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/filters/JwtAuthFilter.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/models/SysGroup.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/models/SysGroupDataPermission.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/models/SysGroupPermission.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/models/SysGroupPermissionKey.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/models/SysRouter.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/models/SysRouterPermission.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/models/SysUser.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/models/SysUserSetting.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/models/SysUserSettingKey.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/models/SysUserView.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/models/Token.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/repositories/SysGroupDao.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/repositories/SysGroupDataPermissionDao.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/repositories/SysGroupPermissionDao.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/repositories/SysRouterDao.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/repositories/SysRouterPermissionDao.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/repositories/SysUserDao.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/repositories/SysUserSettingDao.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/repositories/SysUserViewDao.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/repositories/TokenDao.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/services/AuthorizationService.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/services/MgmUserService.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/services/SysGroupPermissionService.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/services/UserTokenService.java create mode 100644 src/main/java/com/mgm/mcrm/authorization/utils/JwtTokenUtil.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/agebucket/models/SysAgebucket.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/agebucket/repositories/SysAgebucketDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/agebucket/services/AgebucketService.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/ProfileDetail.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/ProfileMemberships.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/VipCode.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/request/AmountLimit.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/request/CompRuleDateRange.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/request/ComplimentaryRuleLimits.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/request/CreateCompRuleRequest.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/request/UpdateCompRuleRequest.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/AccountResponse.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/AgebucketResponse.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/CancelReasonResponse.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/ProfileDetailResponse.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/RequestorApproverResponse.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/ReservationDoorKeyResponse.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/ReservationNoteResponse.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/ReservationQueueResponse.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgBlockCodes.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgCompPreset.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgDaylightConfiguration.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgDaylightMapping.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgDaylightView.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgExceptDaylightRoomTypes.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgExceptionDaylight.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgExceptionDaylightRoomTypesKey.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgExceptionDaylightView.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgExceptionOperaView.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgItemInventory.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgMarketCodes.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgNonMGMStatusMapping.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgOperaView.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgOtherFollowUpStatus.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgOtherSegment.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgRateCodes.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgSourceCodes.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgTiers.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/BlockCodeDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/CompPresetDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/DaylightConfigurationDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/DaylightDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/DaylightViewDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/ExceptionDaylightDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/ExceptionDaylightViewDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/ExceptionOperaDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/ExceptionOperaViewDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/ItemInventoryDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/MarketCodeDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/OperaViewDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/OtherSegmentDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/RateCodeDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/SourceCodeDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/TierDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/daylight/services/DaylightService.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/property/dtos/response/DayLightProfileResponse.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/property/dtos/response/DescriptionResponse.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/property/dtos/response/ResultResponse.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/property/dtos/response/TokenResponse.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/property/models/CfgBlocks.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/property/models/CfgProperties.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/property/repositories/BlockDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/property/repositories/PropertyDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/property/services/PropertyCache.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/room/models/CfgBedTypeMapping.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/room/models/CfgBedTypeMappingView.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/room/models/CfgOtherRoomStatus.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/room/models/CfgRoomFeatures.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/room/models/CfgRoomTypes.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/room/models/CfgRooms.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/room/models/CfgRoomsRoomTypes.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/room/models/CfgRoomsRoomTypesKey.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/room/repositories/BedTypeMappingDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/room/repositories/OtherRoomStatusDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/room/repositories/RoomDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/room/repositories/RoomFeatureDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/room/repositories/RoomRoomTypeDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/room/repositories/RoomTypeDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/room/services/OtherRoomStatusService.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/team/models/AppUsers.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/team/models/CfgDepartments.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/team/models/CfgDivisions.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/team/models/CfgOtherUserMapping.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/team/models/CfgSections.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/team/models/CfgTeamStructure.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/team/models/CfgTeamStructureView.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/team/repositories/AppUserDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/team/repositories/DepartmentDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/team/repositories/DivisionDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/team/repositories/OtherUserMappingDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/team/repositories/SectionDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/team/repositories/TeamStructureDao.java create mode 100644 src/main/java/com/mgm/mcrm/basesetting/team/repositories/TeamStructureViewDao.java create mode 100644 src/main/java/com/mgm/mcrm/booking/controllers/BookingController.java create mode 100644 src/main/java/com/mgm/mcrm/booking/controllers/WaitlistController.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/BookingCancelInfo.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/BookingDateEntry.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/BookingDto.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/BookingUserEntry.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/WebBatchUpdateWaitlistRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/daylight/AmountLock.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/daylight/Breakdown.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/daylight/GuestForBreakdown.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/ChangeMiscChargeRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/AccompanyingGuestDTO.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/IndividualDTO.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/PurchaseElementsWithInventoryItemsDTO.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/ReservationDTO.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/ReservationMembershipDTO.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/ReservationRequestDTO.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/daylight/responses/DistributionChannelResponse.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/daylight/responses/GuaranteeTypeResponse.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CancelBookingIDPair.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CancelBookingIDs.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CancelBookingRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CancelBookingResponse.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CancelBookingResult.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CombineShareRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CombineShareResponse.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingHotelReservation.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingProfile.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingProfileIDs.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingProfiles.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingResGuest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingResGuests.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingResponse.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRoomStay.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRoomStays.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRoomType.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRoomTypeDescription.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRoomTypes.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingUniqueIDList.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAdditionalDetail.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAdditionalDetailDescription.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAdditionalDetails.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAddresses.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAllowance.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAllowanceConvert.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAmount.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAmountConvert.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingArrivalTransport.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingBase.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingBaseConvert.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCancelTerm.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCharges.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingChargesForPostingDate.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingComment.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingComments.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCompany.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCurrentBalance.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCurrentBalanceConvert.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCustomer.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepartureTransport.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepositAmount.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepositAmountConvert.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepositDueAmount.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepositDueAmountConvert.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepositRequired.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDescription.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingExpectedCharges.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingGuarantee.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingGuestCount.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingGuestCounts.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingHotelReference.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingHotelReferenceConvert.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingHotelReservation.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingMemberships.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingNameAddress.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingNameMembership.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingNamePhone.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingOtherPayment.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPackage.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPackageAmount.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPackageAmountConvert.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPackages.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPayment.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPaymentType.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPaymentsAccepted.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPersonName.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPhones.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingProfile.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingProfileIDs.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingProfiles.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRate.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRatePlan.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRatePlanDescription.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRatePlans.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRates.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResGuest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResGuestRPH.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResGuestRPHs.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResGuests.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingReservationGuarantee.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingReservationHistory.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingReservationPaymentInfo.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingReservationPayments.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResponse.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResult.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomRate.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomRateAndPackages.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomRates.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomStay.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomStays.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomToChargeDescription.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomToChargeShortDescription.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomType.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomTypeDescription.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomTypeShortDescription.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomTypes.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingShareReservationDetails.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingShareReservations.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingShortDescription.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTaxAmount.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTaxAmountConvert.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTaxesAndFees.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingText.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTimeSpan.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTotal.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTotalConvert.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingUniqueID.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingUniqueIDConvert.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingUniqueIDList.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingUserDefinedValue.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingUserDefinedValues.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FutureBookingSummaryBase.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FutureBookingSummaryBaseConvert.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/FutureBookingSummaryRate.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/GuestRequestsRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/GuestRequestsResponse.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/GuestRequestsResult.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/InsertGuestCardRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/InsertGuestCardResponse.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/ModifyBookingRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/ModifyBookingResponse.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/UpdatePassportRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/UpdatePassportResponse.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/Comment.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/ConfirmationNumber.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/GuestRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/GuestRequestMsg.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/HotelReference.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/OGHeader.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/SpecialRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/Trace.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/search/BookingQueryRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/search/BookingSearchRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/search/CheckSecondTPDRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/search/CheckTPDRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/search/DateRange.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/search/GetBookingByGroupRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/search/GetBookingByIdRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/search/GetBookingByNameIdRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/search/GetOperaBookingRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/search/PlayerLookupRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/dtos/search/WebRecordSearchRequest.java create mode 100644 src/main/java/com/mgm/mcrm/booking/enums/ProfileTierEnums.java create mode 100644 src/main/java/com/mgm/mcrm/booking/mappers/BookingMapper.java create mode 100644 src/main/java/com/mgm/mcrm/booking/models/Bookings.java create mode 100644 src/main/java/com/mgm/mcrm/booking/models/BookingsView.java create mode 100644 src/main/java/com/mgm/mcrm/booking/models/CfgBookingTypes.java create mode 100644 src/main/java/com/mgm/mcrm/booking/models/GamingData.java create mode 100644 src/main/java/com/mgm/mcrm/booking/models/NonMGMBookings.java create mode 100644 src/main/java/com/mgm/mcrm/booking/models/OWSTransactions.java create mode 100644 src/main/java/com/mgm/mcrm/booking/models/OperaComment.java create mode 100644 src/main/java/com/mgm/mcrm/booking/models/OperaDBBooking.java create mode 100644 src/main/java/com/mgm/mcrm/booking/models/OperaDBRate.java create mode 100644 src/main/java/com/mgm/mcrm/booking/repositories/BookingDao.java create mode 100644 src/main/java/com/mgm/mcrm/booking/repositories/BookingTypeDao.java create mode 100644 src/main/java/com/mgm/mcrm/booking/repositories/BookingViewDao.java create mode 100644 src/main/java/com/mgm/mcrm/booking/repositories/GamingDataDao.java create mode 100644 src/main/java/com/mgm/mcrm/booking/repositories/NonMGMBookingDao.java create mode 100644 src/main/java/com/mgm/mcrm/booking/repositories/NonMGMStatusMappingDao.java create mode 100644 src/main/java/com/mgm/mcrm/booking/repositories/OWSTransactionsRepository.java create mode 100644 src/main/java/com/mgm/mcrm/booking/repositories/OtherAppChannelDao.java create mode 100644 src/main/java/com/mgm/mcrm/booking/repositories/OtherFollowUpStatusDao.java create mode 100644 src/main/java/com/mgm/mcrm/booking/services/BookingService.java create mode 100644 src/main/java/com/mgm/mcrm/booking/services/NonMGMBookingService.java create mode 100644 src/main/java/com/mgm/mcrm/booking/services/OWSTransactionsService.java create mode 100644 src/main/java/com/mgm/mcrm/booking/services/OperaDBBookingService.java create mode 100644 src/main/java/com/mgm/mcrm/booking/services/OperaService.java create mode 100644 src/main/java/com/mgm/mcrm/booking/services/WaitlistBookingService.java create mode 100644 src/main/java/com/mgm/mcrm/booking/services/mockup/BookingServiceMockup.java create mode 100644 src/main/java/com/mgm/mcrm/common/annotation/logging/OperationLog.java create mode 100644 src/main/java/com/mgm/mcrm/common/annotation/security/AccessToken.java create mode 100644 src/main/java/com/mgm/mcrm/common/annotation/security/PassToken.java create mode 100644 src/main/java/com/mgm/mcrm/common/config/DataSourceConfig.java create mode 100644 src/main/java/com/mgm/mcrm/common/config/HttpClientConfig.java create mode 100644 src/main/java/com/mgm/mcrm/common/config/HttpHeader.java create mode 100644 src/main/java/com/mgm/mcrm/common/config/JMSConfig.java create mode 100644 src/main/java/com/mgm/mcrm/common/config/MGMDataSourceConfig.java create mode 100644 src/main/java/com/mgm/mcrm/common/config/OperaDataSourceConfig.java create mode 100644 src/main/java/com/mgm/mcrm/common/config/SwaggerConfig.java create mode 100644 src/main/java/com/mgm/mcrm/common/config/WebFilterConfig.java create mode 100644 src/main/java/com/mgm/mcrm/common/constants/SysCommon.java create mode 100644 src/main/java/com/mgm/mcrm/common/constants/SysConstants.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/BaseApiResponse.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/BaseQueryRequest.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/CachedToken.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/DataTableResult.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/EumnApprovalStatus.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/HttpResult.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/RequestDefination.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/config/APIConfig.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/data_import/ValidateResult.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/data_import/booking/OtherBookingImportRow.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/excel_export/ColumnDefine.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/excel_export/DataElement.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/excel_export/ExportDefination.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/excel_export/ExportSheet.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/excel_model/ColumnDefine.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/excel_model/ColumnGroupInfo.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/excel_model/DataBlock.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/excel_model/ExportDefine.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/excel_model/GroupItem.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/excel_model/ImportDefine.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/excel_model/RowFieldInfo.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/excel_model/SheetDefine.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/http_util/HttpRequestDefine.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/http_util/HttpResponseResult.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/ApprovalGamingDataResult.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/ApproverRecord.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/ApproverRecordResult.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/ApproverResult.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/CheckApproverResult.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/ItemRecord.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/NonMGMBookingApiResult.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/NonMGMBookingRecord.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/PlayerProfileEntry.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/PlayerTPDApiResult.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDashboardRecord.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDashboardResult.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDateListRecord.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDateListResult.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDetailDescription.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDetailResult.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoListRecord.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoListResult.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/UserInfoApiRecord.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/UserInfoApiResult.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/WaitlistBookingApiResult.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/WaitlistBookingRecord.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/WaitlistDataApiResult.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/mgm_api/WaitlistDataRecord.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/msg/AppSettingMsgData.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/msg/JMSTextMessage.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/msg/UpdateCfgItem.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/system/AppServerState.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/system/ResFileResult.java create mode 100644 src/main/java/com/mgm/mcrm/common/dtos/system/RouterPages.java create mode 100644 src/main/java/com/mgm/mcrm/common/enums/DeliveryReceiptState.java create mode 100644 src/main/java/com/mgm/mcrm/common/enums/EnumBookingStatus.java create mode 100644 src/main/java/com/mgm/mcrm/common/enums/HttpMethods.java create mode 100644 src/main/java/com/mgm/mcrm/common/filters/ConfigHeaderFilter.java create mode 100644 src/main/java/com/mgm/mcrm/common/httpclient/HttpClientExecutor.java create mode 100644 src/main/java/com/mgm/mcrm/common/httpclient/HttpCookieContext.java create mode 100644 src/main/java/com/mgm/mcrm/common/httpclient/HttpEntityBuilder.java create mode 100644 src/main/java/com/mgm/mcrm/common/httpclient/HttpHeaderBuilder.java create mode 100644 src/main/java/com/mgm/mcrm/common/httpclient/HttpParameterBuilder.java create mode 100644 src/main/java/com/mgm/mcrm/common/httpclient/HttpRequestOptions.java create mode 100644 src/main/java/com/mgm/mcrm/common/httpclient/HttpSslSupport.java create mode 100644 src/main/java/com/mgm/mcrm/common/interceptor/ControllerLogAspector.java create mode 100644 src/main/java/com/mgm/mcrm/common/jms/AppControlMsgConsumer.java create mode 100644 src/main/java/com/mgm/mcrm/common/jms/AppControlMsgSender.java create mode 100644 src/main/java/com/mgm/mcrm/common/jms/BookingControlMsgConsumer.java create mode 100644 src/main/java/com/mgm/mcrm/common/jms/BookingControlMsgSender.java create mode 100644 src/main/java/com/mgm/mcrm/common/listener/ConfigListener.java create mode 100644 src/main/java/com/mgm/mcrm/common/schedule/AppSystemScheduleJob.java create mode 100644 src/main/java/com/mgm/mcrm/common/schedule/BookingScheduleJob.java create mode 100644 src/main/java/com/mgm/mcrm/common/services/HttpService.java create mode 100644 src/main/java/com/mgm/mcrm/common/services/HttpTokenService.java.bak create mode 100644 src/main/java/com/mgm/mcrm/common/services/MGMApiService.java create mode 100644 src/main/java/com/mgm/mcrm/common/services/SysServerStateService.java create mode 100644 src/main/java/com/mgm/mcrm/common/utils/ADFSUtil.java create mode 100644 src/main/java/com/mgm/mcrm/common/utils/AESUtil.java create mode 100644 src/main/java/com/mgm/mcrm/common/utils/DaoUtil.java create mode 100644 src/main/java/com/mgm/mcrm/common/utils/DateTimeUtil.java create mode 100644 src/main/java/com/mgm/mcrm/common/utils/ETLXstream.java create mode 100644 src/main/java/com/mgm/mcrm/common/utils/EncryptUtil.java create mode 100644 src/main/java/com/mgm/mcrm/common/utils/ExcelUtils.java create mode 100644 src/main/java/com/mgm/mcrm/common/utils/HttpUtil.java create mode 100644 src/main/java/com/mgm/mcrm/common/utils/LogUtil.java create mode 100644 src/main/java/com/mgm/mcrm/common/utils/MailConfig.java create mode 100644 src/main/java/com/mgm/mcrm/common/utils/MessageReceiverListenerImpl.java create mode 100644 src/main/java/com/mgm/mcrm/common/utils/NetworkUtil.java create mode 100644 src/main/java/com/mgm/mcrm/common/utils/PDFUtil.java create mode 100644 src/main/java/com/mgm/mcrm/common/utils/SOAPUtil.java create mode 100644 src/main/java/com/mgm/mcrm/common/utils/SendEmail.java create mode 100644 src/main/java/com/mgm/mcrm/common/utils/XMLBuliderUtil.java create mode 100644 src/main/java/com/mgm/mcrm/common/utils/mockup/AjaxResultMockup.java create mode 100644 src/main/java/com/mgm/mcrm/common/utils/mockup/HttpUtilMockup.java create mode 100644 src/main/java/com/mgm/mcrm/logging/controllers/SysLogAppController.java create mode 100644 src/main/java/com/mgm/mcrm/logging/controllers/SysLogConfirmController.java create mode 100644 src/main/java/com/mgm/mcrm/logging/controllers/SysLogDeviceTokenController.java create mode 100644 src/main/java/com/mgm/mcrm/logging/dtos/AppLogDto.java create mode 100644 src/main/java/com/mgm/mcrm/logging/dtos/MobileConfirmLogRequest.java create mode 100644 src/main/java/com/mgm/mcrm/logging/dtos/request/SaveDeviceTokenRequest.java create mode 100644 src/main/java/com/mgm/mcrm/logging/dtos/request/UpdateDeviceTokenRequest.java create mode 100644 src/main/java/com/mgm/mcrm/logging/dtos/response/SaveDeviceTokenResponse.java create mode 100644 src/main/java/com/mgm/mcrm/logging/dtos/response/UpdateDeviceTokenResponse.java create mode 100644 src/main/java/com/mgm/mcrm/logging/models/SysLogApp.java create mode 100644 src/main/java/com/mgm/mcrm/logging/models/SysLogBooking.java create mode 100644 src/main/java/com/mgm/mcrm/logging/models/SysLogDeviceToken.java create mode 100644 src/main/java/com/mgm/mcrm/logging/models/SysLogETA.java create mode 100644 src/main/java/com/mgm/mcrm/logging/models/SysLogLogin.java create mode 100644 src/main/java/com/mgm/mcrm/logging/models/SysLogLoginIp.java create mode 100644 src/main/java/com/mgm/mcrm/logging/models/SysLogMobileConfirm.java create mode 100644 src/main/java/com/mgm/mcrm/logging/models/SysLogOperation.java create mode 100644 src/main/java/com/mgm/mcrm/logging/repositories/SysLogAppDao.java create mode 100644 src/main/java/com/mgm/mcrm/logging/repositories/SysLogBookingDao.java create mode 100644 src/main/java/com/mgm/mcrm/logging/repositories/SysLogConfirmDao.java create mode 100644 src/main/java/com/mgm/mcrm/logging/repositories/SysLogDeviceTokenDao.java create mode 100644 src/main/java/com/mgm/mcrm/logging/repositories/SysLogETADao.java create mode 100644 src/main/java/com/mgm/mcrm/logging/repositories/SysLogLoginDao.java create mode 100644 src/main/java/com/mgm/mcrm/logging/repositories/SysLogLoginIpDao.java create mode 100644 src/main/java/com/mgm/mcrm/logging/repositories/SysLogOperationDao.java create mode 100644 src/main/java/com/mgm/mcrm/logging/services/SysLogAppService.java create mode 100644 src/main/java/com/mgm/mcrm/logging/services/SysLogBookingService.java create mode 100644 src/main/java/com/mgm/mcrm/logging/services/SysLogConfirmService.java create mode 100644 src/main/java/com/mgm/mcrm/logging/services/SysLogDeviceTokenService.java create mode 100644 src/main/java/com/mgm/mcrm/logging/services/SysLogETAService.java create mode 100644 src/main/java/com/mgm/mcrm/logging/services/SysLogLoginIpService.java create mode 100644 src/main/java/com/mgm/mcrm/logging/services/SysLogLoginService.java create mode 100644 src/main/java/com/mgm/mcrm/logging/services/SysLogOperationService.java create mode 100644 src/main/java/com/mgm/mcrm/notification/config/ApnClientConfig.java create mode 100644 src/main/java/com/mgm/mcrm/notification/controllers/EmailTemplateController.java create mode 100644 src/main/java/com/mgm/mcrm/notification/controllers/NotificationController.java create mode 100644 src/main/java/com/mgm/mcrm/notification/dtos/request/ChangeNotificationStatusRequest.java create mode 100644 src/main/java/com/mgm/mcrm/notification/dtos/request/GenerateBookingEmailRequest.java create mode 100644 src/main/java/com/mgm/mcrm/notification/dtos/request/SendNotificationRequest.java create mode 100644 src/main/java/com/mgm/mcrm/notification/dtos/response/ChangeNotificationStatusResponse.java create mode 100644 src/main/java/com/mgm/mcrm/notification/dtos/response/CountNotificationByUserIdResponse.java create mode 100644 src/main/java/com/mgm/mcrm/notification/dtos/response/GetNotificationResponse.java create mode 100644 src/main/java/com/mgm/mcrm/notification/models/CfgEmailTemplate.java create mode 100644 src/main/java/com/mgm/mcrm/notification/models/Email.java create mode 100644 src/main/java/com/mgm/mcrm/notification/models/SysLogNotification.java create mode 100644 src/main/java/com/mgm/mcrm/notification/repositories/EmailDao.java create mode 100644 src/main/java/com/mgm/mcrm/notification/repositories/EmailTemplateDao.java create mode 100644 src/main/java/com/mgm/mcrm/notification/repositories/SysLogNotificationRepository.java create mode 100644 src/main/java/com/mgm/mcrm/notification/services/ApnNotificationService.java create mode 100644 src/main/java/com/mgm/mcrm/notification/services/EmailTemplateService.java create mode 100644 src/main/java/com/mgm/mcrm/notification/services/NotificationService.java create mode 100644 src/main/java/com/mgm/mcrm/player/controllers/PlayerController.java create mode 100644 src/main/java/com/mgm/mcrm/player/controllers/TodoController.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/BasePricePerDay.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/CancellationReasonResult.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/PlayerProfile.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/PlayerTPD.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/ProjectedRevenue.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/ProjectedRevenueAmount.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/RatePricingDetail.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/StatusCode.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/UserInfo.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/request/EtaRecordInfo.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/request/GetDashboardRequest.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/request/GetTodoDetailRequest.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/request/GetTodoListRequest.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/request/TodoCancelBookingRequest.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/request/TodoChangeDateRequest.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/request/TodoSubmitETARequest.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/request/WebCheckPlayerTPDRequest.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/request/WebPlayerLookupRequest.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/response/CancelReasonResultResponse.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/response/DaylightReservationResponse.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/response/GetDashboardResponse.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/response/GetTodoDetailResponse.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/response/GetTodoListResponse.java create mode 100644 src/main/java/com/mgm/mcrm/player/dtos/response/ReservationResultResponse.java create mode 100644 src/main/java/com/mgm/mcrm/player/services/PlayerService.java create mode 100644 src/main/java/com/mgm/mcrm/player/services/TodoService.java create mode 100644 src/main/resources/AuthKey_79FNU7K4J9_Development.p8 create mode 100644 src/main/resources/application-dev.yml create mode 100644 src/main/resources/application-dev2.yml create mode 100644 src/main/resources/application.yml create mode 100644 src/main/resources/i18n/messages.properties create mode 100644 src/main/resources/i18n/messages_en_US.properties create mode 100644 src/main/resources/i18n/messages_zh_CN.properties create mode 100644 src/main/resources/i18n/messages_zh_TW.properties create mode 100644 src/main/resources/idp-metadata.xml create mode 100644 src/main/resources/logback.xml create mode 100644 src/main/resources/mcrm.willtechmacau.com.pfx create mode 100644 src/main/resources/mockup/app/getBlock.json create mode 100644 src/main/resources/mockup/app/getBookingsByNameId.json create mode 100644 src/main/resources/mockup/app/getCriteria.json create mode 100644 src/main/resources/mockup/app/getProperty.json create mode 100644 src/main/resources/mockup/app/getRoom.json create mode 100644 src/main/resources/mockup/app/getRoomType.json create mode 100644 src/main/resources/mockup/app/getSpecial.json create mode 100644 src/main/resources/mockup/app/getTodoDashboard_1.json create mode 100644 src/main/resources/mockup/app/getTodoDashboard_2.json create mode 100644 src/main/resources/mockup/app/getTodoDashboard_3.json create mode 100644 src/main/resources/mockup/app/getTodoDashboard_4.json create mode 100644 src/main/resources/mockup/app/getTodoDetail_1.json create mode 100644 src/main/resources/mockup/app/getTodoDetail_2.json create mode 100644 src/main/resources/mockup/app/getTodoDetail_3.json create mode 100644 src/main/resources/mockup/app/getTodoDetail_4.json create mode 100644 src/main/resources/mockup/app/getTodoList_1.json create mode 100644 src/main/resources/mockup/app/getTodoList_2.json create mode 100644 src/main/resources/mockup/app/getTodoList_3.json create mode 100644 src/main/resources/mockup/app/getTodoList_4.json create mode 100644 src/main/resources/mockup/app/getTodoList_5.json create mode 100644 src/main/resources/mockup/app/getTodoList_6.json create mode 100644 src/main/resources/mockup/app/getTodoList_7.json create mode 100644 src/main/resources/mockup/app/getTodoList_8.json create mode 100644 src/main/resources/mockup/app/getTodoList_9.json create mode 100644 src/main/resources/mockup/app/playerProfile.json create mode 100644 src/main/resources/mockup/app/submitETA.json create mode 100644 src/main/resources/mockup/approval/getApprovalData.json create mode 100644 src/main/resources/mockup/approval/getApprover.json create mode 100644 src/main/resources/mockup/http/check_player_tpd_all_pass.json create mode 100644 src/main/resources/mockup/http/check_player_tpd_not_all_pass.json create mode 100644 src/main/resources/mockup/http/check_player_tpd_partly_pass.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res1.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res10.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res11.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res12.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res13.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res14.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res15.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res16.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res17.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res18.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res19.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res2.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res20.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res21.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res22.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res23.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res24.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res25.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res26.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res27.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res28.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res29.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res3.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res30.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res31.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res4.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res5.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res6.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res7.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res8.json create mode 100644 src/main/resources/mockup/http/get_player_profile_api_res9.json create mode 100644 src/main/resources/mockup/http/get_user_info_api_res1.json create mode 100644 src/main/resources/mockup/http/get_user_info_api_res10.json create mode 100644 src/main/resources/mockup/http/get_user_info_api_res11.json create mode 100644 src/main/resources/mockup/http/get_user_info_api_res12.json create mode 100644 src/main/resources/mockup/http/get_user_info_api_res13.json create mode 100644 src/main/resources/mockup/http/get_user_info_api_res14.json create mode 100644 src/main/resources/mockup/http/get_user_info_api_res15.json create mode 100644 src/main/resources/mockup/http/get_user_info_api_res16.json create mode 100644 src/main/resources/mockup/http/get_user_info_api_res17.json create mode 100644 src/main/resources/mockup/http/get_user_info_api_res2.json create mode 100644 src/main/resources/mockup/http/get_user_info_api_res3.json create mode 100644 src/main/resources/mockup/http/get_user_info_api_res4.json create mode 100644 src/main/resources/mockup/http/get_user_info_api_res5.json create mode 100644 src/main/resources/mockup/http/get_user_info_api_res6.json create mode 100644 src/main/resources/mockup/http/get_user_info_api_res7.json create mode 100644 src/main/resources/mockup/http/get_user_info_api_res8.json create mode 100644 src/main/resources/mockup/http/get_user_info_api_res9.json create mode 100644 src/main/resources/mockup/http/non_mgm_booking_no_record.json create mode 100644 src/main/resources/mockup/http/non_mgm_booking_with_record.json create mode 100644 src/main/resources/mockup/mgm_api_mockup_def.json create mode 100644 src/main/resources/mockup/system/login.json create mode 100644 src/main/resources/static/WM.png create mode 100644 src/main/resources/static/WP.png create mode 100644 src/main/resources/static/logon1.png create mode 100644 src/main/resources/templates/mfalogin.shtml create mode 100644 src/test/java/com/mgm/daylight/EnumBookingStatusTest.java create mode 100644 src/test/java/com/mgm/daylight/HttpEntityBuilderTest.java create mode 100644 src/test/java/com/mgm/daylight/SmallTest.java create mode 100644 src/test/java/com/mgm/mcrm/booking/controllers/BookingControllerRecordSearchTest.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..53c65de --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +/crm_runtime/logs/ +/.idea/ +/.claude/ +/.vscode/ +/target/* +!/target/crm_mobile_runtime/ +/.classpath +/.project diff --git a/CRMMobileApi.iml b/CRMMobileApi.iml new file mode 100644 index 0000000..a10b566 --- /dev/null +++ b/CRMMobileApi.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/crm_mobile_runtime/appconfig.properties b/crm_mobile_runtime/appconfig.properties new file mode 100644 index 0000000..51acda8 --- /dev/null +++ b/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/crm_mobile_runtime/convert/bin/BookingService$1.class b/crm_mobile_runtime/convert/bin/BookingService$1.class new file mode 100644 index 0000000000000000000000000000000000000000..39d5a8b306431aec43a2c748d1a3cd6280ac9c41 GIT binary patch literal 7513 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 AX8-^I literal 0 HcmV?d00001 diff --git a/crm_mobile_runtime/convert/bin/BookingService.class b/crm_mobile_runtime/convert/bin/BookingService.class new file mode 100644 index 0000000000000000000000000000000000000000..abc5f29233f8b10c2965232cbc5f44496d4f7f2f GIT binary patch literal 135728 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
-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 Do^Sv? literal 0 HcmV?d00001 diff --git a/crm_mobile_runtime/excel_define/import/import_other_booking.json b/crm_mobile_runtime/excel_define/import/import_other_booking.json new file mode 100644 index 0000000..c8805e6 --- /dev/null +++ b/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 + } + ] + }] + }] +} diff --git a/crm_runtime/convert/bin/BookingService$1.class b/crm_runtime/convert/bin/BookingService$1.class new file mode 100644 index 0000000000000000000000000000000000000000..39d5a8b306431aec43a2c748d1a3cd6280ac9c41 GIT binary patch literal 7513 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 AX8-^I literal 0 HcmV?d00001 diff --git a/crm_runtime/convert/bin/BookingService.class b/crm_runtime/convert/bin/BookingService.class new file mode 100644 index 0000000000000000000000000000000000000000..abc5f29233f8b10c2965232cbc5f44496d4f7f2f GIT binary patch literal 135728 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
-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 Do^Sv? literal 0 HcmV?d00001 diff --git a/docs/merge_daylight_dl_reservation_dedup.md b/docs/merge_daylight_dl_reservation_dedup.md new file mode 100644 index 0000000..e0195ce --- /dev/null +++ b/docs/merge_daylight_dl_reservation_dedup.md @@ -0,0 +1,101 @@ +# Daylight 合并与 `dl_reservation_id` 去重说明 + +本文档说明 `BookingService` 中为减少「同一 Daylight 预订在 `bookings` 表出现多行」所做的修改及调用关系。 + +--- + +## 1. 涉及文件与入口 + +| 位置 | 说明 | +|------|------| +| `BookingService.java` | `mergeDaylightRecordToDatabaseInfo`、`insertDaylightBooking`、`consolidateDuplicateDlReservations` 及相关私有辅助方法 | +| `BookingController`(recordSearch 等) | 在拉取 Daylight 列表后调用 `mergeDaylightRecordToDatabaseInfo` | + +--- + +## 2. `mergeDaylightRecordToDatabaseInfo` 的改动要点 + +### 2.1 预查询:按 `dlReservationId` 收集(不再依赖确认号) + +**原问题**:仅当 `confirmationNo` 非空时才把 `dlReservationId` 放进 `findByDlReservationIdIn` 的入参。若接口有 `dl_reservation_id` 但尚未返回确认号,则查不到库里已有行,会误判为「不存在」而走插入,产生重复。 + +**现逻辑**:对本次 `result`(Daylight 返回列表)中每条记录,只要 `dlReservationId` 非空白即加入 `LinkedHashSet`,再转为 `List` 做 `findByDlReservationIdIn`。 + +### 2.2 合并后物理去重:`consolidateDuplicateDlReservations` + +在 `updateBookingList` 执行 `bookingDao.saveAll` **之后**,对本次涉及到的每个 `dl_reservation_id` 再查库: + +- 若同一 `dl_reservation_id` 仍对应 **≥2 行**(例如一条前台 `PN`、一条同步误插入的 `N`),则: + - 按评分规则选出 **keeper(主行)**,其余为 **duplicate(次行)**; + - 将次行上可对齐的字段并入主行后 **`delete` 次行**。 + +**主行评分** `keeperScoreForDlDedup`(分数高者优先): + +- 有 `player_id`:+1000 +- `approve_status == "PN"`:+100 +- 有 `confirmation_no`:+10 +- 有 `member`:+5 + +同分按 **较小 `id`** 靠前(作为 keeper)。 + +**不合并、不删除** `shouldSkipConsolidatingDuplicateRow`: + +- 次行 `approve_status` 以 `W` 开头(候补等) +- 次行 `revision_of` 指向 keeper(待审批修订子单) +- keeper `revision_of` 指向次行 + +**字段合并** `mergeDuplicateBookingIntoKeeper`: + +- 确认号、`resv_id`、Opera 状态、酒店/客源/房价码、`player_id`、`member` 与姓名字段、房/房型、`booking_type_id`、`chain_code`、`block_id` 等在主行为空或可从次行安全补齐时写入主行;**`last_opera_status`** 若次行有值则写入主行(与 Opera 同步一致)。 + +日志前缀:`[consolidateDuplicateDlReservations]`。 + +--- + +## 3. `insertDaylightBooking` 的改动要点 + +### 3.1 按 `dl_reservation_id` 兜底防插 + +在组好 `Bookings book` 并准备 `save` **之前**,若 `operaBooking.getDlReservationId()` 非空,则先 `findByDlReservationIdIn`: + +- **若已存在任一行**:**不再 `save` 新单**,打日志 `[insertDaylightBooking] skip insert, existing dl_reservation_id=...`,并设置返回视图上的 `id` 等为已有记录,直接 `return operaBooking`。 + +避免「合并阶段漏匹配」时再次插入第二条同 `dl_reservation_id`。 + +### 3.2 按确认号防重(空列表才插入) + +- 仅当 `confirmationNo` 非空时执行 `findByConfirmationNo`; +- **仅当查询结果为空** 时才 `bookingDao.save(book)`; +- 若已有同确认号记录,则复用其 `id`,**不重复插入**。 + +--- + +## 4. 根因归纳(与旧版对比) + +| 原因 | 说明 | +|------|------| +| 预查漏掉无确认号的 `dl_reservation_id` | 已用 `LinkedHashSet` + 非空 `dlReservationId` 修复 | +| 仅合并不删重复行 | 已用 `consolidateDuplicateDlReservations` 在当次同步末尾收敛 | +| 插入路径无 `dl_reservation_id` 防重 / 确认号逻辑不当 | 已在 `insertDaylightBooking` 中补齐 | +| 数据库无唯一约束 | **仍建议在库上对非空 `dl_reservation_id` 做过滤唯一索引**(上线前清理历史重复) | +| 并发双写 | 当前以逻辑合并 + 完成后去重为主;多实例强一致可再加分布式锁或 DB 唯一约束 | + +--- + +## 5. 运维与验证 + +1. **验证**:部署后对曾出现双行的会员再触发一次会走 `mergeDaylightRecordToDatabaseInfo` 的查询(如 recordSearch);观察日志中 `consolidateDuplicateDlReservations` 是否合并并删除次行。 +2. **历史数据**:长期未再走合并流程的重复行,需一次性脚本或手工按业务规则保留主行、删除/归档次行。 +3. **外键**:若 `delete` 次行失败(子表引用),需先迁移或删除子表记录后再删。 + +--- + +## 6. 可选后续增强(未列入当前分支必选) + +- 合并匹配改为 `Strings.CI.equals`(忽略 `dl_reservation_id` 大小写),与接口/库实际存储一致。 +- 对 `mergeDaylightRecordToDatabaseInfo` 增加 `@Transactional(rollbackFor = Exception.class)`,使 `saveAll` 与 `consolidateDuplicateDlReservations` 同事务回滚。 +- 高并发下对同一 `dl_reservation_id` 的插入加应用层锁或依赖唯一索引 + 捕获冲突后改走更新。 + +--- + +*文档与 `daylight_1.0.0` 分支中 `BookingService` 当前实现对应;若行号随重构变化请以方法名为准。* diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..130381d --- /dev/null +++ b/pom.xml @@ -0,0 +1,253 @@ + + 4.0.0 + + will + CRMMobileApi + 1.0.1-SNAPSHOT + jar + + CRMMobileApi + + + org.springframework.boot + spring-boot-starter-parent + 3.5.13 + + + + + 21 + 1.5.25 + 6.3.1 + 2.21.2 + 10.1.54 + 6.2.18 + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-mail + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-activemq + + + org.apache.activemq + activemq-client + 6.2.4 + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-aop + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.8.17 + + + com.microsoft.sqlserver + mssql-jdbc + + + org.apache.httpcomponents.client5 + httpclient5 + 5.5 + + + org.apache.httpcomponents.client5 + httpclient5-win + 5.2.1 + + + org.springframework.boot + spring-boot-starter-tomcat + + + com.google.code.gson + gson + + + org.springframework + spring-context-support + + + org.testng + testng + 7.7.0 + + + com.alibaba + fastjson + 2.0.50 + + + org.apache.poi + poi + 5.4.1 + + + org.apache.poi + poi-ooxml + 5.4.1 + + + commons-io + commons-io + 2.16.1 + + + org.apache.commons + commons-lang3 + 3.18.0 + + + org.apache.commons + commons-text + 1.14.0 + + + org.jsoup + jsoup + 1.15.3 + + + org.springframework.boot + spring-boot-devtools + true + + + com.auth0 + java-jwt + 4.5.0 + + + org.jsmpp + jsmpp + 2.3.11 + + + com.thoughtworks.xstream + xstream + 1.4.21 + + + jakarta.xml.soap + jakarta.xml.soap-api + 3.0.2 + + + com.sun.xml.messaging.saaj + saaj-impl + + + xmlpull + xmlpull + 1.1.3.4a + + + jakarta.xml.bind + jakarta.xml.bind-api + 4.0.4 + + + org.springframework + spring-messaging + + + + org.locationtech.jts + jts-core + 1.18.2 + + + org.projectlombok + lombok + provided + + + org.mapstruct + mapstruct + 1.6.3 + + + org.projectlombok + lombok-mapstruct-binding + 0.2.0 + + + org.mapstruct + mapstruct-processor + 1.6.3 + + + com.eatthepath + pushy + 0.15.4 + + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + com.mgm.mcrm.CRMMobileApplication + + + + + repackage + + + + + + maven-compiler-plugin + + ${java.version} + UTF-8 + + + + org.codehaus.mojo + license-maven-plugin + 2.7.0 + + + EPL-1.0 + LGPL-2.1 + + + + + + + + CRM Mobile Api + diff --git a/src/main/java/com/mgm/mcrm/CRMMobileApplication.java b/src/main/java/com/mgm/mcrm/CRMMobileApplication.java new file mode 100644 index 0000000..823b750 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/CRMMobileApplication.java @@ -0,0 +1,29 @@ +package com.mgm.mcrm; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.boot.web.servlet.ServletComponentScan; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.jms.annotation.EnableJms; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.transaction.annotation.EnableTransactionManagement; + + +@SpringBootApplication +@ComponentScan(basePackages="com.mgm.mcrm") +@EntityScan(basePackages="com.mgm.mcrm") +@EnableTransactionManagement +@ServletComponentScan +@EnableScheduling +@EnableAsync +@EnableJms +@EnableCaching +public class CRMMobileApplication{ + public static void main( String[] args ) { + SpringApplication.run(CRMMobileApplication.class, args); + + } +} diff --git a/src/main/java/com/mgm/mcrm/TestRun.java b/src/main/java/com/mgm/mcrm/TestRun.java new file mode 100644 index 0000000..6a7af41 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/TestRun.java @@ -0,0 +1,11 @@ +package com.mgm.mcrm; + + +import java.util.UUID; + +public class TestRun { + public static void main(String[] args) { + + System.out.println(UUID.randomUUID()); + } +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/adfs/config/HttpClientContextRequestFactory.java b/src/main/java/com/mgm/mcrm/adfs/config/HttpClientContextRequestFactory.java new file mode 100644 index 0000000..a0b83b9 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/adfs/config/HttpClientContextRequestFactory.java @@ -0,0 +1,25 @@ +package com.mgm.mcrm.adfs.config; + +import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.springframework.http.HttpMethod; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; + +import java.net.URI; + +public class HttpClientContextRequestFactory extends HttpComponentsClientHttpRequestFactory { + private HttpClientContext sharedContext; + + public void setContext(HttpClientContext context) { + this.sharedContext=context; + } + + @Override + protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) { + if (this.sharedContext != null) { + return this.sharedContext; + } + return super.createHttpContext(httpMethod, uri); + } + +} diff --git a/src/main/java/com/mgm/mcrm/adfs/controllers/SSOCallbackController.java b/src/main/java/com/mgm/mcrm/adfs/controllers/SSOCallbackController.java new file mode 100644 index 0000000..6bd5949 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/adfs/controllers/SSOCallbackController.java @@ -0,0 +1,39 @@ +package com.mgm.mcrm.adfs.controllers; + +import java.io.IOException; +import java.io.PrintWriter; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +//@RequestMapping("/sso_callback") +@Controller +public class SSOCallbackController { + @RequestMapping(value="/sso_callback/login",method = RequestMethod.GET) + public String ssoLoginCallback(HttpServletRequest request, HttpServletResponse response) throws IOException{ + String text = "Login Callback!"; + // 设置内容类型和字符编码 + response.setContentType("text/html"); + response.setCharacterEncoding("UTF-8"); + PrintWriter out = response.getWriter(); + out.print(text); + out.close(); + return null; + } + + @RequestMapping(value="/sso_callback/logout",method = RequestMethod.GET) + public String ssoLogoutCallback(HttpServletRequest request, HttpServletResponse response) throws IOException{ + String text = "Logout Callback!"; + // 设置内容类型和字符编码 + response.setContentType("text/html"); + response.setCharacterEncoding("UTF-8"); + PrintWriter out = response.getWriter(); + out.print(text); + out.close(); + return null; + } +} diff --git a/src/main/java/com/mgm/mcrm/adfs/controllers/SSORestProcessController.java b/src/main/java/com/mgm/mcrm/adfs/controllers/SSORestProcessController.java new file mode 100644 index 0000000..0f0f1ff --- /dev/null +++ b/src/main/java/com/mgm/mcrm/adfs/controllers/SSORestProcessController.java @@ -0,0 +1,952 @@ +package com.mgm.mcrm.adfs.controllers; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.net.InetAddress; +import java.net.URI; +import java.net.URLEncoder; +import java.net.UnknownHostException; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.mgm.mcrm.adfs.config.HttpClientContextRequestFactory; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.apache.hc.client5.http.auth.*; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.cookie.*; +import org.apache.hc.client5.http.entity.UrlEncodedFormEntity; +import org.apache.hc.client5.http.impl.DefaultRedirectStrategy; +import org.apache.hc.client5.http.impl.auth.*; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.cookie.BasicClientCookie; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy; +import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; +import org.apache.hc.core5.http.*; +import org.apache.hc.core5.http.message.BasicNameValuePair; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.ssl.SSLContexts; +import org.apache.hc.core5.util.Timeout; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpMethod; +import org.springframework.http.client.ClientHttpRequest; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.stereotype.Controller; +import org.springframework.util.StreamUtils; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.util.HtmlUtils; + +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.utils.AESUtil; +import com.mgm.mcrm.common.utils.LogUtil; +import com.mgm.mcrm.common.utils.NetworkUtil; + +import javax.net.ssl.SSLContext; + + +@Controller +@RequestMapping("/api") +public class SSORestProcessController { + @Value("${sso.callback.login.success}") + private String loginCallbackUrl; + @Value("${sso.callback.logout.success}") + private String logoutCallbackUrl; + @Value("${adfs.hostname}") + private String adfsHost; + @Value("${relying_party}") + private String relyingParty; + @Value("${ad_domain}") + private String adDomain; + @Value("${host_name}") + private String hostName; + @Value("${adfs_domain}") + private String adfsDomain; + @Value("${adfs_secret_key}") + private String adfsSecretKey; + + @Value("${adfs_request_timeout}") + private int adfsRequestTimeout=10000; + @Value("${adfs_login_timeout}") + private int adfsLoginTimeout=60000; + private static final String TEXT_SPLIT_CHAR = ","; + + private Map cookieSetting = new HashMap(); + + private boolean checkValidUrl(String requestUrl){ + boolean isValid = NetworkUtil.isValidURL(requestUrl); + if(isValid){ + if(!requestUrl.startsWith(loginCallbackUrl) + && !requestUrl.startsWith(adfsHost)){ + isValid =false; + } + } + return isValid; + } + + private void initCookieSetting() { + if(cookieSetting.size()<=0) { + String[] adfsCookiePath = new String[] {"/adfs"}; + cookieSetting.put(adfsDomain, adfsCookiePath); + String[] localCookiePath = new String[] {"/","/adfs"}; + cookieSetting.put("LOCALHOST", localCookiePath); + LogUtil.info(SSORestProcessController.class,"Init Cookie Setting:"+adfsDomain); + } + } + + private String getWorkstationName() { + try { + return InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + return "localhost"; + } + } + + private Credentials createNtlmCredentials(String username, String password, + String domain, String workstation) { + String effectiveWorkstation = workstation; + if (effectiveWorkstation == null || effectiveWorkstation.isEmpty()) { + effectiveWorkstation = getWorkstationName(); + } + return new NTCredentials(username, password.toCharArray(), + effectiveWorkstation, domain); + } + + @RequestMapping(value="/app/sso/login_saml_with_mfa") + public String samlMFALogin(HttpServletRequest request, HttpServletResponse response) throws Exception{ + String paraRelying = StringUtils.isNotBlank(request.getParameter("relyingParty"))?request.getParameter("relyingParty"):relyingParty; + String authorizedUrl = adfsHost+ "/adfs/ls/IdpInitiatedSignOn.aspx?loginToRp="+paraRelying; + String requestClientId = request.getParameter("client_request_id"); + Map cookieValues = new HashMap(); + if(StringUtils.isBlank(requestClientId)) { + requestClientId = UUID.randomUUID().toString(); + } + HttpClientContext context = HttpClientContext.create(); + authorizedUrl+="&client-request-id="+ requestClientId; + authorizedUrl+="&RedirectToIdentityProvider="+ URLEncoder.encode("AD AUTHORITY","UTF-8"); + String userName = request.getParameter("username"); + //For DEV test +// if(!StringUtils.isEmpty(userName)) { +// userName = Strings.CS.replace(userName, "@mgm.mo", ""); +// } + Credentials credentials =null; + + LogUtil.info(SSORestProcessController.class,"userName:"+userName); + String password = request.getParameter("password"); + String credentialId=request.getParameter("credentialId"); + String credentialData=request.getParameter("credentialData"); + String authMethod = request.getParameter("AuthMethod"); + String mfaContent = request.getParameter("Context"); + String eventTarget = request.getParameter("__EVENTTARGET"); + String[] urlKeyword = { + "/sso_callback/login" + }; + Enumeration paraNames = request.getParameterNames(); + if(paraNames!=null) { + while(paraNames.hasMoreElements()) { + String paraName = paraNames.nextElement(); + if(StringUtils.startsWith(paraName, "Cookie_")) { + String cookieName = paraName.replace("Cookie_", ""); + cookieValues.put(cookieName, request.getParameter(paraName)); + } + } + } + if(StringUtils.isNotBlank(credentialId) && StringUtils.isNotBlank(credentialData)) { + userName = AESUtil.AES256Decrypt(adfsSecretKey, credentialId); + password = AESUtil.AES256Decrypt(adfsSecretKey, credentialData); + } + boolean validateParas = true; + String errorCode =""; + String errorMessage =""; + if(StringUtils.isBlank(userName)||StringUtils.isBlank(password)) { + errorCode="InvalidParas"; + errorMessage="User name or password is blank"; + validateParas=false; + }else if(StringUtils.isNotBlank(authMethod) && StringUtils.isBlank(mfaContent)) { + errorCode="InvalidMFAParas"; + errorMessage="MFA content is blank"; + validateParas=false; + } + if(!validateParas) { + String redirectUrl = loginCallbackUrl+"?"; + redirectUrl+=("error="+URLEncoder.encode(errorCode,"UTF-8")); + redirectUrl+=("&errorMessage="+URLEncoder.encode(errorMessage,"UTF-8")); + response.sendRedirect(redirectUrl); + }else { + CookieStore cookieStore = new BasicCookieStore(); + SystemDefaultCredentialsProvider credentialsProvider = new SystemDefaultCredentialsProvider(); + String adUserName = userName; + //LogUtil.info(SSORestProcessController.class,"Ad domain with account :"+adUserName); + AuthScope authScope = new AuthScope(null, -1); + credentials = createNtlmCredentials(adUserName, password, adDomain, null); + credentialsProvider.setCredentials(authScope, credentials); + + SSLContext sslContext = SSLContexts.custom() + .loadTrustMaterial((chain, authType) -> true) // 信任所有证书 + .build(); + NoopHostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE; + DefaultClientTlsStrategy tlsStrategy = new DefaultClientTlsStrategy(sslContext, hostnameVerifier); + PoolingHttpClientConnectionManager connectionManager = + PoolingHttpClientConnectionManagerBuilder.create() + .setTlsSocketStrategy(tlsStrategy) + .setMaxConnTotal(100) + .setMaxConnPerRoute(10) + .build(); + + HttpClientBuilder clientBuilder = HttpClients.custom().setConnectionManager(connectionManager); + RequestConfig defaultConfig = RequestConfig.custom() + .setCookieSpec(StandardCookieSpec.RELAXED) + .setConnectionRequestTimeout(Timeout.ofMicroseconds(adfsRequestTimeout)) + .setAuthenticationEnabled(true) + .setCircularRedirectsAllowed(true) + .setMaxRedirects(10) + .setRedirectsEnabled(true) + .build(); + clientBuilder.setDefaultRequestConfig(defaultConfig).setDefaultCookieStore(cookieStore); + clientBuilder.setRedirectStrategy(new DefaultRedirectStrategy(){ + @Override + public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException { + boolean isNeedRedirect = false; + int statusCode = response.getCode(); + if(statusCode == 301 || statusCode == 302 || statusCode == 303 || statusCode == 305 || statusCode == 307 || statusCode == 308){ + isNeedRedirect =true; + Header[] redirectHeads = response.getHeaders("location"); + if(redirectHeads!=null && redirectHeads.length>0) { + //LogUtil.info(SSORestProcessController.class,"Visit Link:"+request.getRequestUri()); + String location = redirectHeads[0].getValue(); + for(String keyWord:urlKeyword) { + if(location.contains(keyWord)) { + isNeedRedirect=false; + break; + } + } + } + } + return isNeedRedirect; + } + }); + if(!cookieValues.isEmpty()) { + initCookieSetting(); + Set cookieKeys = cookieValues.keySet(); + for(String cookieKey:cookieKeys) { + try { + String cookieVal = cookieValues.get(cookieKey); + LogUtil.info(SSORestProcessController.class,"Set Cookie ["+cookieKey+"]="+cookieVal); + if(cookieSetting!=null && !cookieSetting.isEmpty()) { + Iterator cookieSetKeys = cookieSetting.keySet().iterator(); + while(cookieSetKeys.hasNext()) { + String cookieDomain =cookieSetKeys.next(); + String[] cookiePaths = cookieSetting.get(cookieDomain); + if(cookiePaths!=null) { + if(Strings.CI.equals("LOCALHOST", cookieDomain)) { + cookieDomain=""; + } + for(String cookiePath:cookiePaths) { + BasicClientCookie cookie = new BasicClientCookie(cookieKey, cookieVal); + try { + Date currentDate = new Date(); + Date expiryDate = new Date(currentDate.getTime() + 1800 * 1000); + cookie.setExpiryDate(expiryDate); + }catch(Exception ignored) { + + } + cookie.setPath(cookiePath); + cookie.setDomain(cookieDomain); + cookie.setSecure(true); + cookie.setAttribute("httponly", "true"); + cookieStore.addCookie(cookie); + } + } + } + } + } catch (Exception err) { + LogUtil.error(SSORestProcessController.class,"Set Cookie failed :"+err.getMessage()); + } + } + } + clientBuilder.setDefaultCookieStore(cookieStore); + clientBuilder.setDefaultCredentialsProvider(credentialsProvider); + + context.setCookieStore(cookieStore); + context.setCredentialsProvider(credentialsProvider); + + CloseableHttpClient httpClient = clientBuilder.build(); + //HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient); + HttpClientContextRequestFactory httpFactory = new HttpClientContextRequestFactory(); + httpFactory.setHttpClient(httpClient); + httpFactory.setContext(context); + + String stepCode ="Start"; + if(StringUtils.isNotBlank(mfaContent)) { + stepCode ="CheckMFAStatus"; + } + + String requestUrl = authorizedUrl; + boolean isProcessEnd=false; + Map httpResult = null; + Date startTime = new Date(); + Date lastResTime = new Date(); + int pendingInterval = 2000; + Map responseHeaders = null; + while(!isProcessEnd) { + LogUtil.info(SSORestProcessController.class,"Current Step:["+stepCode+"]"); + if("Start".equals( stepCode)) { + requestUrl = authorizedUrl; + httpResult = this.processStartStep(httpFactory, requestUrl, userName, password,credentials,responseHeaders); + }else if("Redirect".equals(stepCode)){ + httpResult = this.processStartStep(httpFactory, requestUrl, userName, password,credentials,responseHeaders); + }else if("verifyMFA".equals(stepCode)){ + httpResult = this.processMFAStep(httpFactory, requestUrl, userName, password,context); + }else if("CheckMFAStatus".equals(stepCode)) { + httpResult = this.processCheckMFAStatus(httpFactory, requestUrl, authMethod,mfaContent,eventTarget,userName, password,context); + } + if("Pending".equals(stepCode)) { + Date currentTime = new Date(); + if(currentTime.getTime()-lastResTime.getTime()>=pendingInterval) { + stepCode = "Start"; + }else { + Thread.sleep(500); + } + }else { + isProcessEnd = this.verifyResult(httpResult,cookieStore,urlKeyword,userName,password,requestClientId); + if(httpResult!=null && httpResult.get("ResponseHeaders")!=null) + responseHeaders = (Map)httpResult.get("ResponseHeaders"); + if(!isProcessEnd) { + Date currentTime = new Date(); + if(currentTime.getTime()-startTime.getTime()>=adfsLoginTimeout) { + isProcessEnd =true; + httpResult.put("NextStep","Callback"); + httpResult.put("ErrorCode", "Login Time Out"); + httpResult.put("ErrorMessage", "Login processing exceeded "+(adfsLoginTimeout/1000)+" seconds"); + }else { + stepCode=httpResult.get("NextStep")==null?"Pending":httpResult.get("NextStep").toString(); + requestUrl = httpResult.get("NextUrl")==null?"":httpResult.get("NextUrl").toString(); + } + } + lastResTime=new Date(); + } + } + this.processResult(response, httpResult,loginCallbackUrl); + } + return null; + } + + + private Map processStartStep(HttpClientContextRequestFactory httpFactory,String loginUrl, String userName, String password, Credentials credentials,Map extraHeaders) throws Exception { + LogUtil.info(SSORestProcessController.class,"Process Start URL:"+loginUrl); + Map result = new HashMap(); + result.put("CurrentStep", "Start"); + ClientHttpResponse clientResponse = null; + String errorMessage =""; + String errorCode=""; + if(!checkValidUrl(loginUrl)){ + throw new Exception("Invalid url:"+loginUrl); + } + try { + ClientHttpRequest request = httpFactory.createRequest(new URI(loginUrl), HttpMethod.POST); + request.getHeaders().add("User-Agent", "Java-NTLM-Client"); + request.getHeaders().add("Accept", "*/*"); + request.getHeaders().add("Connection", "Keep-Alive"); + request.getHeaders().add("content-type", "application/x-www-form-urlencoded"); + if(extraHeaders!=null) { + extraHeaders.forEach((key, value) -> { + //LogUtil.info(SSORestProcessController.class,"Expend Header:"+key+" Value:"+value); + if(!"content-type".equalsIgnoreCase(key)){ + request.getHeaders().add(key, NetworkUtil.sanitizeHeaderValue(value)); + } + }); + } + + List form = new ArrayList<>(); + form.add(new BasicNameValuePair("UserName", userName)); + form.add(new BasicNameValuePair("password", password)); + form.add(new BasicNameValuePair("AuthMethod", "FormsAuthentication")); + form.add(new BasicNameValuePair("Kmsi", "True")); + UrlEncodedFormEntity entity = new UrlEncodedFormEntity(form, StandardCharsets.UTF_8); + StreamUtils.copy(entity.getContent(), request.getBody()); + clientResponse = request.execute(); + }catch(Exception err) { + errorCode="RequestFailed"; + errorMessage = err.getMessage(); + LogUtil.error(SSORestProcessController.class,"Start step failed :"+err.getMessage()); + } + result.put("HttpResponse", clientResponse); + result.put("ErrorMessage", errorMessage); + result.put("ErrorCode", errorCode); + return result; + } + + private Map processMFAStep(HttpClientContextRequestFactory httpFactory,String loginUrl, String userName, String password,HttpClientContext context) throws Exception { + LogUtil.info(SSORestProcessController.class,"Process MFA URL:"+loginUrl); + Map result = new HashMap(); + result.put("CurrentStep", "verifyMFA"); + ClientHttpResponse clientResponse = null; + String errorMessage =""; + String errorCode=""; + if(!checkValidUrl(loginUrl)){ + throw new Exception("Invalid url:"+loginUrl); + } + try { + ClientHttpRequest request = httpFactory.createRequest(new URI(loginUrl), HttpMethod.POST); + request.getHeaders().add("content-type", "application/x-www-form-urlencoded"); + List form = new ArrayList<>(); + form.add(new BasicNameValuePair("UserName", userName)); + form.add(new BasicNameValuePair("password", password)); + form.add(new BasicNameValuePair("AuthMethod", "AzureMfaAuthentication")); + UrlEncodedFormEntity entity = new UrlEncodedFormEntity(form, StandardCharsets.UTF_8); + StreamUtils.copy(entity.getContent(), request.getBody()); + clientResponse = request.execute(); + }catch(Exception err) { + errorCode="RequestFailed"; + errorMessage = err.getMessage(); + } + result.put("HttpResponse", clientResponse); + result.put("ErrorMessage", errorMessage); + result.put("ErrorCode", errorCode); + return result; + } + + private Map processCheckMFAStatus(HttpClientContextRequestFactory httpFactory, + String requestUrl, String authMethod, String mfaContent,String eventTarget,String userName, String password,HttpClientContext context) throws Exception { + LogUtil.info(SSORestProcessController.class,"Check MFA Status URL:"+requestUrl); + Map result = new HashMap(); + result.put("CurrentStep", "CheckMFAStatus"); + ClientHttpResponse clientResponse = null; + String errorMessage =""; + String errorCode=""; + if(!checkValidUrl(requestUrl)){ + throw new Exception("Invalid url:"+requestUrl); + } + try { + ClientHttpRequest request = httpFactory.createRequest(new URI(requestUrl), HttpMethod.POST); + request.getHeaders().add("content-type", "application/x-www-form-urlencoded"); + List form = new ArrayList<>(); + form.add(new BasicNameValuePair("UserName", userName)); + form.add(new BasicNameValuePair("password", password)); + form.add(new BasicNameValuePair("AuthMethod", authMethod)); + form.add(new BasicNameValuePair("Context", mfaContent)); + form.add(new BasicNameValuePair("__EVENTTARGET", eventTarget)); + UrlEncodedFormEntity entity = new UrlEncodedFormEntity(form, StandardCharsets.UTF_8); + StreamUtils.copy(entity.getContent(), request.getBody()); + clientResponse = request.execute(); + }catch(Exception err) { + errorCode="RequestFailed"; + errorMessage = err.getMessage(); + } + result.put("HttpResponse", clientResponse); + result.put("ErrorMessage", errorMessage); + result.put("ErrorCode", errorCode); + return result; + } + + private String checkErrorMessage(String responseBody) { + String errorText =""; + String errRex = "<(\\S+) id=\"errorText\"(.*?)>(.*?)(.*?) httpResult,CookieStore cookieStore,String[] urlKeyword,String userName, String password,String clientRequestId) throws IOException { + boolean isEnd=false; + if(httpResult!=null) { + if(httpResult.get("HttpResponse")!=null) { + String currentStep = httpResult.get("CurrentStep")==null?"":httpResult.get("CurrentStep").toString(); + ClientHttpResponse clientResponse = (ClientHttpResponse)httpResult.get("HttpResponse"); + int statusCode = clientResponse.getStatusCode().value(); + LogUtil.info(SSORestProcessController.class,"Verify Status Code:"+statusCode+" current step:"+currentStep); + Map resHeaders = new HashMap(); + clientResponse.getHeaders().forEach((key, value) -> value.forEach(it -> { + //LogUtil.info(SSORestProcessController.class,"Response Header:"+key+" Value:"+value); + resHeaders.put(key, it); + })); + httpResult.put("ResponseHeaders", resHeaders); + httpResult.put("ResponseCookies", cookieStore.getCookies()); + httpResult.put("StatusCode", statusCode+""); + if(statusCode==401) { + httpResult.put("ErrorCode", "401"); + httpResult.put("ErrorMessage", "Authorization Failed"); + isEnd=true; + }else if(statusCode==302 || statusCode==301 || statusCode == 303 || statusCode == 305 || statusCode == 307 || statusCode == 308) { + String redirectUrl = clientResponse.getHeaders().get("Location").getFirst(); + //LogUtil.info(SSORestProcessController.class,"Checking Redirect URL:"+redirectUrl); + httpResult.put("NextStep", "Redirect"); + httpResult.put("NextUrl", redirectUrl); + if(urlKeyword!=null) { + for(String urlKey:urlKeyword) { + if(Strings.CS.contains(redirectUrl, urlKey)) { + isEnd=true; + } + } + } + }else if(statusCode==200) { + StringBuilder stringBuilder = new StringBuilder(); + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(clientResponse.getBody(), "UTF-8")); + String line = null; + while ((line = reader.readLine()) != null) { + stringBuilder.append(line); + } + }catch(Exception err) { + LogUtil.info(SSORestProcessController.class,"Read Response Body Failed:"+err.getMessage()); + } + String responseBody = stringBuilder.toString(); + LogUtil.info(SSORestProcessController.class,"Response 200:["+responseBody+"]"); + responseBody = responseBody.replace("", "\n"); + responseBody = responseBody.replace("//", ""); + + httpResult.put("NextStep", "Pending"); + String mfaOptionUrl = ""; + if(Strings.CS.contains(responseBody, "form id=\"options\"")) { + String regex = "action=\\\"(.+?)\\\""; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(responseBody); + if(matcher.find()) { + mfaOptionUrl = matcher.group(1); + } + } + + String errorText =this.checkErrorMessage(responseBody); + if(StringUtils.isNotBlank(errorText)) { + isEnd=true; + String errorCode = "AdfsError"; + if(Strings.CS.contains(currentStep, "CheckMFAStatus")) { + errorCode = "MFAStatusFailed"; + }else if(Strings.CS.contains(responseBody, "id=\"authOptions\"")) { + errorCode = "MFALoginFailed"; + }else if(Strings.CS.contains(responseBody, "id=\"loginForm\"")) { + errorCode = "FormLoginFailed"; + } + httpResult.put("NextStep", "Callback"); + httpResult.put("ErrorCode", errorCode); + httpResult.put("ErrorMessage", errorText); + }else { + isEnd=true; + boolean existsMFAContent = Strings.CS.contains(responseBody, " resCookies = httpResult.get("ResponseCookies")!=null?(List)httpResult.get("ResponseCookies"):null; + String extractInfo = "\n "; + extractInfo+= "\n "; + extractInfo+= "\n "; + if(cookieStore!=null) { + for (Cookie cookie : cookieStore.getCookies()) { + extractInfo+= "\n "; + } + } + extractInfo+= "\n httpResult,String callbackUrl) throws Exception { + if(httpResult!=null) { + LogUtil.info(SSORestProcessController.class,"Process Result response"); + String nextStep = httpResult.get("NextStep")!=null?httpResult.get("NextStep").toString():""; + String nextUrl = httpResult.get("NextUrl")!=null?httpResult.get("NextUrl").toString():""; + String errorCode = httpResult.get("ErrorCode")!=null?httpResult.get("ErrorCode").toString():""; + String statusCode = httpResult.get("StatusCode")!=null?httpResult.get("StatusCode").toString():""; + String errorMessage = httpResult.get("ErrorMessage")!=null?httpResult.get("ErrorMessage").toString():""; + Map resHeaders = httpResult.get("ResponseHeaders")!=null?(Map)httpResult.get("ResponseHeaders"):null; + if(resHeaders!=null) { + resHeaders.forEach((key, value) -> { + try { + //LogUtil.info(SSORestProcessController.class,"Res Header:"+key+" Value:"+value); + response.setHeader(key, NetworkUtil.sanitizeHeaderValue(value)); + }catch(Exception ignored) { + + } + }); + } + if(Strings.CS.equals(nextStep, "ReturnResult")||Strings.CS.equals(nextStep, "Pending")) { + String responseBody = httpResult.get("ResponseBody")!=null?httpResult.get("ResponseBody").toString():""; + //LogUtil.info(SSORestProcessController.class,"Response Body:"+responseBody); + byte[] outputData = responseBody.getBytes(); + long contentLength = outputData.length; + response.setHeader("Content-Length", Long.toString(contentLength)); + StreamUtils.copy(outputData, response.getOutputStream()); + }else if(Strings.CS.equals(nextStep, "Redirect")){ + String redirectUrl = nextUrl; + if(!checkValidUrl(redirectUrl)){ + throw new Exception("Invalid redirect url:"+redirectUrl); + } + if(StringUtils.isBlank(response.getHeader("Location"))) { + LogUtil.info(SSORestProcessController.class,"Redirect location:"+redirectUrl); + response.setHeader("Location", NetworkUtil.sanitizeHeaderValue(redirectUrl)); + } + response.sendRedirect(redirectUrl); + }else { + String redirectUrl = callbackUrl+"?"; + redirectUrl+=("errorCode="+URLEncoder.encode(errorCode,"UTF-8")); + redirectUrl+=("&errorMessage="+URLEncoder.encode(errorMessage,"UTF-8")); + if(!checkValidUrl(redirectUrl)){ + throw new Exception("Invalid redirect url:"+redirectUrl); + } + response.setHeader("Location", NetworkUtil.sanitizeHeaderValue(redirectUrl)); + response.setHeader("Content-Length","0"); + LogUtil.info(SSORestProcessController.class,"Callback with ErrorCode:"+redirectUrl+" [errorMessage]:"+errorMessage); + response.sendRedirect(redirectUrl); + } + }else { + String redirectUrl = callbackUrl+"?errorCode=Invalid_Result&errorMessage=Invalid_Result"; + if(!checkValidUrl(redirectUrl)){ + throw new Exception("Invalid redirect url:"+redirectUrl); + } + response.setHeader("Location", NetworkUtil.sanitizeHeaderValue(redirectUrl)); + response.setHeader("Content-Length","0"); + response.sendRedirect(redirectUrl); + } + } + + + @RequestMapping(value="/app/sso/export_folder",method = RequestMethod.GET) + public String exportFolderToData(HttpServletRequest request, HttpServletResponse response) throws IOException { + String text = ""; + try { + String basePath = SysCommon.runtime_path + "\\"+SysCommon.runtimeName+"\\convert\\bin\\"; + File directory = new File(basePath); + List parentFolders = new ArrayList(); + List childFolders = null; + List filesExport = new ArrayList(); + parentFolders.add(directory); + while(!parentFolders.isEmpty()) { + childFolders = new ArrayList(); + for(File dir:parentFolders) { + File[] fileList = dir.listFiles(); + if(fileList!=null && fileList.length>0) { + for(File subFile:fileList) { + if(subFile.isDirectory()) { + childFolders.add(subFile); + }else { + filesExport.add(subFile); + } + } + } + } + parentFolders = childFolders; + } + if(filesExport.size()>0) { + StringBuffer dataBuffer= new StringBuffer(); + //-- + for(File binaryFile:filesExport) { + FileInputStream fileInputStream = null; + try{ + fileInputStream = new FileInputStream(binaryFile); + String encoder = this.encode(fileInputStream); + String filePath = binaryFile.getPath().replace(basePath, ""); + if (encoder != null) { + if(dataBuffer.length()>0) { + dataBuffer.append(";"); + } + dataBuffer.append("[{"+filePath+"};{"+encoder+"}]"); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + if(fileInputStream != null) { + try { + fileInputStream.close(); + } catch (IOException ie) { + ie.printStackTrace(); + } + } + } + } + //-- + String outputFilePath = SysCommon.runtime_path + "\\"+SysCommon.runtimeName+"\\convert\\text\\exportfile.data"; + File outputFile = new File(outputFilePath); + if(!outputFile.exists()) + outputFile.createNewFile(); + BufferedWriter bufferedWriter = null; + try { + bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFile))); + String totalContent = dataBuffer.toString(); + bufferedWriter.write(totalContent); + bufferedWriter.flush(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (bufferedWriter != null) { + try { + bufferedWriter.close(); + } catch (IOException ie) { + ie.printStackTrace(); + } + } + } + } + text += "Export total "+filesExport.size()+" files to exportfile.data"; + }catch (Exception err) { + text += err.getMessage(); + } + // 设置内容类型和字符编码 + response.setContentType("text/plain"); + response.setCharacterEncoding("UTF-8"); + PrintWriter out = response.getWriter(); + out.print(text); + out.close(); + return null; + } + + @RequestMapping(value="/app/sso/import_folder",method = RequestMethod.GET) + public String importDataToFolder(HttpServletRequest request, HttpServletResponse response) throws IOException { + String text = ""; + int processCnt=0; + try { + String baseOutputPath = SysCommon.runtime_path + "\\"+SysCommon.runtimeName+"\\convert\\bin\\"; + File dataFile = new File(SysCommon.runtime_path + "\\"+SysCommon.runtimeName+"\\convert\\text\\exportfile.data"); + if(dataFile.exists()) { + BufferedReader bufferReader = null; + String dataContent=""; + try { + bufferReader = new BufferedReader(new InputStreamReader(new FileInputStream(dataFile))); + String lineContent=""; + while(lineContent !=null) { + lineContent = bufferReader.readLine(); + if(lineContent!=null) { + dataContent+=lineContent; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + if(StringUtils.isNotBlank(dataContent)) { + String[] segmentParts = dataContent.split("\\];\\["); + if(segmentParts!=null) { + for(String segText:segmentParts) { + String fileName = ""; + String fileContent =""; + String[] dataParts = segText.split("\\};\\{"); + for(int i=0;i0) { + String fileFolderName = fullFileName.substring(0,pathIndex); + File fileFolder = new File(fileFolderName); + if(!fileFolder.exists() || !fileFolder.isDirectory()) { + fileFolder.mkdirs(); + } + } + File outputFile = new File(fullFileName); + if (!outputFile.exists()) + outputFile.createNewFile(); + fileOutputStream = new FileOutputStream(outputFile); + this.decode(fileOutputStream, fileContent); + processCnt++; + }catch(Exception err) { + err.printStackTrace(); + }finally { + if (fileOutputStream != null) { + try { + fileOutputStream.close(); + } catch (IOException ie) { + ie.printStackTrace(); + } + } + } + } + } + } + text="Import "+processCnt+" files."; + }else { + text="Empty Content."; + } + }else { + text="Data file not found."; + } + }catch (Exception err) { + text+= err.getMessage(); + } + // 设置内容类型和字符编码 + response.setContentType("text/plain"); + response.setCharacterEncoding("UTF-8"); + PrintWriter out = response.getWriter(); + out.print(text); + out.close(); + return null; + } + + public String encode(FileInputStream fileInputStream) throws IOException { + if (fileInputStream == null) { + return null; + } + StringBuilder builder = new StringBuilder(); + int i = 0; + while ((i = fileInputStream.read()) != -1) { + builder.append(i + TEXT_SPLIT_CHAR); + } + return builder.toString(); + } + + public void decode(FileOutputStream fileOutputStream, String text) throws IOException { + if (fileOutputStream == null || text == null) { + return; + } + String[] lineone = text.split(TEXT_SPLIT_CHAR); + for (int j = 0; j < lineone.length; j++) { + fileOutputStream.write(Integer.valueOf(lineone[j])); + } + fileOutputStream.flush(); + } + public void binaryToText(String binaryFilePath, String textFilePath) throws IOException { + File binaryFile = new File(binaryFilePath); + if (!binaryFile.exists()) { + System.out.println("Bin file not exists:"+binaryFilePath); + return; + } + File textFile = new File(textFilePath); + if (!textFile.exists()) + textFile.createNewFile(); + + FileInputStream fileInputStream = null; + BufferedWriter bufferedWriter = null; + + try { + fileInputStream = new FileInputStream(binaryFile); + bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(textFile))); + + String encoder = this.encode(fileInputStream); + if (encoder != null) { + bufferedWriter.write(encoder); + bufferedWriter.flush(); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (fileInputStream != null) { + try { + fileInputStream.close(); + } catch (IOException ie) { + ie.printStackTrace(); + } + } + if (bufferedWriter != null) { + try { + bufferedWriter.close(); + } catch (IOException ie) { + ie.printStackTrace(); + } + } + } + } + + + public void textToBinary(String textFilePath, String binaryFilePath) throws IOException { + File textFile = new File(textFilePath); + if (!textFile.exists()) { + System.out.println("Text File not exists:"+textFilePath); + return; + } + File binaryFile = new File(binaryFilePath); + if (!binaryFile.exists()) + binaryFile.createNewFile(); + + FileOutputStream fileOutputStream = null; + BufferedReader bufferedReader = null; + + try { + fileOutputStream = new FileOutputStream(binaryFile); + bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(textFile))); + this.decode(fileOutputStream, bufferedReader.readLine()); + + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (fileOutputStream != null) { + try { + fileOutputStream.close(); + } catch (IOException ie) { + ie.printStackTrace(); + } + } + if (bufferedReader != null) { + try { + bufferedReader.close(); + } catch (IOException ie) { + ie.printStackTrace(); + } + } + } + } + + +} + + diff --git a/src/main/java/com/mgm/mcrm/allotment/models/CfgAppChannel.java b/src/main/java/com/mgm/mcrm/allotment/models/CfgAppChannel.java new file mode 100644 index 0000000..07ca560 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/allotment/models/CfgAppChannel.java @@ -0,0 +1,36 @@ +package com.mgm.mcrm.allotment.models; + +import java.io.Serializable; +import java.util.Date; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.Table; +import lombok.Data; + +@Data +@Entity +@Table(name="cfg_app_channel") +@IdClass(CfgAppChannelKey.class) +public class CfgAppChannel { + + @Id + @Column(name="criteria_id") + private Long criteriaId; + @Id + @Column(name="block_id") + private Long blockId; + @Column(name="created_at") + private Date createdAt; + @Column(name="created_by") + private String createdBy; + @Column(name="app_channel") + private Integer appChannel; + @Column(name="picked_up") + private Integer pickedUp; + @Column(name="available") + private Integer available; + +} diff --git a/src/main/java/com/mgm/mcrm/allotment/models/CfgAppChannelDaylight.java b/src/main/java/com/mgm/mcrm/allotment/models/CfgAppChannelDaylight.java new file mode 100644 index 0000000..feaed8b --- /dev/null +++ b/src/main/java/com/mgm/mcrm/allotment/models/CfgAppChannelDaylight.java @@ -0,0 +1,30 @@ +package com.mgm.mcrm.allotment.models; + +import jakarta.persistence.*; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +@Data +@Entity +@Table(name="cfg_app_channel_daylight") +@IdClass(CfgAppChannelDaylightKey.class) +public class CfgAppChannelDaylight implements Serializable { + @Id + @Column(name="criteria_id") + private Long criteriaId; + @Id + @Column(name="block_code_id") + private Long blockCodeId; + @Column(name="created_at") + private LocalDateTime createdAt; + @Column(name="created_src") + private String createdSource; + @Column(name="channel_total") + private Integer channelTotal; + @Column(name="picked_up") + private Integer pickedUp; + @Column(name="available") + private Integer available; +} diff --git a/src/main/java/com/mgm/mcrm/allotment/models/CfgAppChannelDaylightKey.java b/src/main/java/com/mgm/mcrm/allotment/models/CfgAppChannelDaylightKey.java new file mode 100644 index 0000000..8fe16bc --- /dev/null +++ b/src/main/java/com/mgm/mcrm/allotment/models/CfgAppChannelDaylightKey.java @@ -0,0 +1,29 @@ +package com.mgm.mcrm.allotment.models; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Objects; + +@Data +public class CfgAppChannelDaylightKey implements Serializable{ + + private Long criteriaId; + private Long blockCodeId; + + @Override + public boolean equals(Object o) { + if(o instanceof CfgAppChannelDaylightKey key) + { + return Objects.equals(this.criteriaId, key.getCriteriaId()) && + Objects.equals(this.blockCodeId, key.getBlockCodeId()); + } + return false ; + } + + @Override + public int hashCode() { + return 1; + } + +} diff --git a/src/main/java/com/mgm/mcrm/allotment/models/CfgAppChannelKey.java b/src/main/java/com/mgm/mcrm/allotment/models/CfgAppChannelKey.java new file mode 100644 index 0000000..81835c7 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/allotment/models/CfgAppChannelKey.java @@ -0,0 +1,46 @@ +package com.mgm.mcrm.allotment.models; + +import java.io.Serializable; + +public class CfgAppChannelKey implements Serializable{ + + private static final long serialVersionUID = 6060166117433738174L; + private Long criteriaId; + private Long blockId; + + public Long getCriteriaId() { + return criteriaId; + } + + public void setCriteriaId(Long criteriaId) { + this.criteriaId = criteriaId; + } + + public Long getBlockId() { + return blockId; + } + + public void setBlockId(Long blockId) { + this.blockId = blockId; + } + + @Override + public boolean equals(Object o) { + if(o instanceof CfgAppChannelKey) + { + CfgAppChannelKey key = (CfgAppChannelKey)o ; + if(this.criteriaId == key.getCriteriaId() && + this.blockId == key.getBlockId()) + { + return true ; + } + } + return false ; + } + + @Override + public int hashCode() { + return 1; + } + +} diff --git a/src/main/java/com/mgm/mcrm/allotment/models/CfgOtherAllotment.java b/src/main/java/com/mgm/mcrm/allotment/models/CfgOtherAllotment.java new file mode 100644 index 0000000..ddd6d92 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/allotment/models/CfgOtherAllotment.java @@ -0,0 +1,195 @@ +package com.mgm.mcrm.allotment.models; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Set; + +import jakarta.persistence.*; + +import com.mgm.mcrm.basesetting.daylight.models.CfgOtherSegment; + +@Entity +@Table(name="cfg_other_allotment") +public class CfgOtherAllotment implements Serializable { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="property_id") + private Long propertyId; + + @Column(name="book_date") + private Date bookDate; + + @Column(name="room_id") + private Long roomId; + + @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="is_waitlist") + private Integer isWaitlist; + + @Column(name="sharer") + private Integer sharer; + + @Column(name="dow") + private Integer bookDow; + + @Transient + private List appChannel; + + @Column(name="rate") + private Integer rate; + + @Transient + private ArrayList dateRange; + + @Transient + private ArrayList dow; + + //@NotFound(action = NotFoundAction.IGNORE) + @OneToMany(fetch = FetchType.EAGER) + @JoinColumn(name="allotment_id",insertable=false ,updatable=false) + private Set channels; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getPropertyId() { + return propertyId; + } + + public void setPropertyId(Long propertyId) { + this.propertyId = propertyId; + } + + public Date getBookDate() { + return bookDate; + } + + public void setBookDate(Date bookDate) { + this.bookDate = bookDate; + } + + public Long getRoomId() { + return roomId; + } + + public void setRoomId(Long roomId) { + this.roomId = roomId; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + public Integer getIsWaitlist() { + return isWaitlist; + } + + public void setIsWaitlist(Integer isWaitlist) { + this.isWaitlist = isWaitlist; + } + + public Integer getSharer() { + return sharer; + } + + public void setSharer(Integer sharer) { + this.sharer = sharer; + } + + public ArrayList getDow() { + return dow; + } + + public void setDow(ArrayList dow) { + this.dow = dow; + } + + public Integer getRate() { + return rate; + } + + public void setRate(Integer rate) { + this.rate = rate; + } + + public ArrayList getDateRange() { + return dateRange; + } + + public void setDateRange(ArrayList dateRange) { + this.dateRange = dateRange; + } + + public Integer getBookDow() { + return bookDow; + } + + public void setBookDow(Integer bookDow) { + this.bookDow = bookDow; + } + + public Set getChannels() { + return channels; + } + + public void setChannels(Set channels) { + this.channels = channels; + } + + public List getAppChannel() { + return appChannel; + } + + public void setAppChannel(List appChannel) { + this.appChannel = appChannel; + } + +} diff --git a/src/main/java/com/mgm/mcrm/allotment/models/CfgOtherAllotmentView.java b/src/main/java/com/mgm/mcrm/allotment/models/CfgOtherAllotmentView.java new file mode 100644 index 0000000..4bf1daf --- /dev/null +++ b/src/main/java/com/mgm/mcrm/allotment/models/CfgOtherAllotmentView.java @@ -0,0 +1,331 @@ +package com.mgm.mcrm.allotment.models; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; +import java.util.Set; + +import com.mgm.mcrm.basesetting.property.models.CfgProperties; +import com.mgm.mcrm.basesetting.room.models.CfgRoomTypes; +import com.mgm.mcrm.basesetting.room.models.CfgRooms; +import jakarta.persistence.*; + +import org.hibernate.annotations.NotFound; +import org.hibernate.annotations.NotFoundAction; +import com.mgm.mcrm.basesetting.daylight.models.CfgOtherSegment; + +@Entity +@Table(name="cfg_other_allotment") +@NamedEntityGraphs({ + @NamedEntityGraph( + name = "graph.OtherAllotment.fulldetails", + attributeNodes = { + @NamedAttributeNode("property"), + @NamedAttributeNode("room"), + @NamedAttributeNode("channels"), + @NamedAttributeNode("roomType") + } + ) +}) +public class CfgOtherAllotmentView implements Serializable { + + @Id + @Column(name = "id") + private Long id; + @Column(name="property_id") + private Long propertyId; + + @Column(name="book_date") + private Date bookDate; + + @Column(name="room_id") + private Long roomId; + + @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; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="property_id",insertable=false ,updatable=false) + private CfgProperties property; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="room_id",insertable=false ,updatable=false) + private CfgRooms room; + + @Column(name="is_waitlist") + private Integer isWaitlist; + + @Column(name="sharer") + private Integer sharer; + + @Transient + private Integer totalAllotment; + + @Transient + private List appChannel; + + //@NotFound(action = NotFoundAction.IGNORE) + @OneToMany(fetch = FetchType.EAGER) + @JoinColumn(name="allotment_id",insertable=false ,updatable=false) + private Set channels; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name="cfg_rooms_room_types",joinColumns={@JoinColumn(name="room_id")},inverseJoinColumns={@JoinColumn(name="room_type_id")}) + private Set roomType ; + + @Column(name="rate") + private Integer rate; + + @Column(name="dow") + private Integer bookDow; + + //-- Attribute for export + @Transient + private String propertyName; + @Transient + private String bookDateText; + @Transient + private String bookWeekDay; + @Transient + private String roomCategory; + @Transient + private String roomTypeNames; + @Transient + private List channelList; + @Transient + private String rateValue; + @Transient + private String sharerValue; + @Transient + private String waitListValue; + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getPropertyId() { + return propertyId; + } + + public void setPropertyId(Long propertyId) { + this.propertyId = propertyId; + } + + public Date getBookDate() { + return bookDate; + } + + public void setBookDate(Date bookDate) { + this.bookDate = bookDate; + } + + public Long getRoomId() { + return roomId; + } + + public void setRoomId(Long roomId) { + this.roomId = roomId; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + public CfgProperties getProperty() { + return property; + } + + public void setProperty(CfgProperties property) { + this.property = property; + } + + public CfgRooms getRoom() { + return room; + } + + public void setRoom(CfgRooms room) { + this.room = room; + } + + public Integer getIsWaitlist() { + return isWaitlist; + } + + public void setIsWaitlist(Integer isWaitlist) { + this.isWaitlist = isWaitlist; + } + + public Set getRoomType() { + return roomType; + } + + public void setRoomType(Set roomType) { + this.roomType = roomType; + } + + public Integer getSharer() { + return sharer; + } + + public void setSharer(Integer sharer) { + this.sharer = sharer; + } + + public Integer getRate() { + return rate; + } + + public void setRate(Integer rate) { + this.rate = rate; + } + + + public String getPropertyName() { + return propertyName; + } + + public void setPropertyName(String propertyName) { + this.propertyName = propertyName; + } + + public String getBookDateText() { + return bookDateText; + } + + public void setBookDateText(String bookDateText) { + this.bookDateText = bookDateText; + } + + public String getBookWeekDay() { + return bookWeekDay; + } + + public void setBookWeekDay(String bookWeekDay) { + this.bookWeekDay = bookWeekDay; + } + + public String getRoomCategory() { + return roomCategory; + } + + public void setRoomCategory(String roomCategory) { + this.roomCategory = roomCategory; + } + + public String getRoomTypeNames() { + return roomTypeNames; + } + + public void setRoomTypeNames(String roomTypeNames) { + this.roomTypeNames = roomTypeNames; + } + + public String getRateValue() { + return rateValue; + } + + public void setRateValue(String rateValue) { + this.rateValue = rateValue; + } + + public String getSharerValue() { + return sharerValue; + } + + public void setSharerValue(String sharerValue) { + this.sharerValue = sharerValue; + } + + public String getWaitListValue() { + return waitListValue; + } + + public void setWaitListValue(String waitListValue) { + this.waitListValue = waitListValue; + } + public Integer getBookDow() { + return bookDow; + } + + public void setBookDow(Integer bookDow) { + this.bookDow = bookDow; + } + + public List getAppChannel() { + return appChannel; + } + + public void setAppChannel(List appChannel) { + this.appChannel = appChannel; + } + + public Set getChannels() { + return channels; + } + + public void setChannels(Set channels) { + this.channels = channels; + } + + public List getChannelList() { + return channelList; + } + + public void setChannelList(List channelList) { + this.channelList = channelList; + } + + public Integer getTotalAllotment() { + return totalAllotment; + } + + public void setTotalAllotment(Integer totalAllotment) { + this.totalAllotment = totalAllotment; + } + +} diff --git a/src/main/java/com/mgm/mcrm/allotment/models/CfgOtherAppChannel.java b/src/main/java/com/mgm/mcrm/allotment/models/CfgOtherAppChannel.java new file mode 100644 index 0000000..2b02661 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/allotment/models/CfgOtherAppChannel.java @@ -0,0 +1,76 @@ +package com.mgm.mcrm.allotment.models; + +import java.io.Serializable; +import java.util.Date; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.Table; + +@Entity +@Table(name="cfg_other_app_channel") +@IdClass(CfgOtherAppChannelKey.class) +public class CfgOtherAppChannel implements Serializable { + @Id + @Column(name="allotment_id") + private Long allotmentId; + @Id + @Column(name="segment_id") + private Long segmentId; + @Column(name="created_at") + private Date createdAt; + @Column(name="created_by") + private String createdBy; + @Column(name="app_channel") + private Integer appChannel; + @Column(name="picked_up") + private Integer pickedUp; + @Column(name="available") + private Integer available; + + public Date getCreatedAt() { + return createdAt; + } + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + public String getCreatedBy() { + return createdBy; + } + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + public Integer getAppChannel() { + return appChannel; + } + public void setAppChannel(Integer appChannel) { + this.appChannel = appChannel; + } + public Integer getPickedUp() { + return pickedUp; + } + public void setPickedUp(Integer pickedUp) { + this.pickedUp = pickedUp; + } + public Integer getAvailable() { + return available; + } + public void setAvailable(Integer available) { + this.available = available; + } + public Long getAllotmentId() { + return allotmentId; + } + public void setAllotmentId(Long allotmentId) { + this.allotmentId = allotmentId; + } + public Long getSegmentId() { + return segmentId; + } + public void setSegmentId(Long segmentId) { + this.segmentId = segmentId; + } + +} diff --git a/src/main/java/com/mgm/mcrm/allotment/models/CfgOtherAppChannelKey.java b/src/main/java/com/mgm/mcrm/allotment/models/CfgOtherAppChannelKey.java new file mode 100644 index 0000000..58b7cf8 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/allotment/models/CfgOtherAppChannelKey.java @@ -0,0 +1,50 @@ +package com.mgm.mcrm.allotment.models; + +import java.io.Serializable; + +public class CfgOtherAppChannelKey implements Serializable{ + + private static final long serialVersionUID = 2391575510596099248L; + private Long allotmentId; + private Long segmentId; + + @Override + public boolean equals(Object o) { + if(o instanceof CfgOtherAppChannelKey) + { + CfgOtherAppChannelKey key = (CfgOtherAppChannelKey)o ; + if(this.allotmentId == key.getAllotmentId() && + this.segmentId == key.getSegmentId()) + { + return true ; + } + } + return false ; + } + + @Override + public int hashCode() { + return segmentId.intValue()*1000000 + allotmentId.intValue(); + } + + public Long getAllotmentId() { + return allotmentId; + } + + public void setAllotmentId(Long allotmentId) { + this.allotmentId = allotmentId; + } + + public Long getSegmentId() { + return segmentId; + } + + public void setSegmentId(Long segmentId) { + this.segmentId = segmentId; + } + + public static long getSerialversionuid() { + return serialVersionUID; + } + +} diff --git a/src/main/java/com/mgm/mcrm/allotment/models/CfgRoomCriterias.java b/src/main/java/com/mgm/mcrm/allotment/models/CfgRoomCriterias.java new file mode 100644 index 0000000..8e345ed --- /dev/null +++ b/src/main/java/com/mgm/mcrm/allotment/models/CfgRoomCriterias.java @@ -0,0 +1,100 @@ +package com.mgm.mcrm.allotment.models; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; +import java.util.Set; + +import com.mgm.mcrm.basesetting.daylight.models.CfgBlockCodes; +import com.mgm.mcrm.basesetting.property.models.CfgProperties; +import com.mgm.mcrm.basesetting.room.models.CfgRoomTypes; +import com.mgm.mcrm.basesetting.room.models.CfgRooms; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.persistence.Transient; + +import lombok.Data; +import org.hibernate.annotations.NotFound; +import org.hibernate.annotations.NotFoundAction; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.mgm.mcrm.basesetting.property.models.CfgBlocks; + +@Entity +@Data +@Table(name="cfg_room_criterias") +public class CfgRoomCriterias implements Serializable { + //fields in table + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="property_id") + private Long propertyId; + + @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") + @Column(name="book_date") + private Date bookDate; + + @Column(name="room_id") + private Long roomId; + + @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="dow") + private Integer bookDow; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="property_id",insertable=false ,updatable=false) + private CfgProperties property; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="room_id",insertable=false ,updatable=false) + private CfgRooms room; + + @Column(name="is_waitlist") + private Integer isWaitlist; + + @Column(name="sharer") + private Integer sharer; + + @Transient + private List appChannel; + + @OneToMany(fetch = FetchType.EAGER) + @JoinColumn(name="criteria_id",insertable=false ,updatable=false) + private Set channels; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name="cfg_rooms_room_types",joinColumns={@JoinColumn(name="room_id")},inverseJoinColumns={@JoinColumn(name="room_type_id")}) + private Set roomType ; + + @Column(name="rate") + private Integer rate; + + + +} diff --git a/src/main/java/com/mgm/mcrm/allotment/models/CfgRoomCriteriasDaylight.java b/src/main/java/com/mgm/mcrm/allotment/models/CfgRoomCriteriasDaylight.java new file mode 100644 index 0000000..f2b205a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/allotment/models/CfgRoomCriteriasDaylight.java @@ -0,0 +1,67 @@ +package com.mgm.mcrm.allotment.models; + +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.persistence.*; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Set; + +@Data +@Entity +@Table(name = "cfg_room_criterias_daylight") +public class CfgRoomCriteriasDaylight implements Serializable { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name = "property_id") + private Long propertyId; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @Column(name = "book_date") + private LocalDateTime bookDate; + + @Column(name = "room_id") + private Long roomId; + + @Column(name = "created_at") + private LocalDateTime createdAt; + + @Column(name = "created_by") + private String createdBy; + + @Column(name = "updated_at") + private LocalDateTime updatedAt; + + @Column(name = "updated_by") + private String updatedBy; + + @Column(name = "is_waitlist") + private Integer isWaitlist; + + @Column(name = "sharer") + private Integer sharer; + + @Column(name = "dow") + private Integer bookDow; + +// @Transient +// private List blockCodeChannels; + + @Column(name = "rate") + private Integer rate; + + @Transient + private ArrayList dateRange; + + @Transient + private ArrayList dow; + + @OneToMany(fetch = FetchType.EAGER) + @JoinColumn(name = "criteria_id", insertable = false, updatable = false) + private Set channels; + +} diff --git a/src/main/java/com/mgm/mcrm/allotment/models/CfgRoomCriteriasDaylightView.java b/src/main/java/com/mgm/mcrm/allotment/models/CfgRoomCriteriasDaylightView.java new file mode 100644 index 0000000..f9c5d73 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/allotment/models/CfgRoomCriteriasDaylightView.java @@ -0,0 +1,113 @@ +package com.mgm.mcrm.allotment.models; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.mgm.mcrm.basesetting.daylight.models.CfgBlockCodes; +import com.mgm.mcrm.basesetting.property.models.CfgProperties; +import com.mgm.mcrm.basesetting.room.models.CfgRoomTypes; +import com.mgm.mcrm.basesetting.room.models.CfgRooms; +import jakarta.persistence.*; +import lombok.Data; +import org.hibernate.annotations.NotFound; +import org.hibernate.annotations.NotFoundAction; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Set; + +@Data +@Entity +@Table(name = "cfg_room_criterias_daylight") +@NamedEntityGraphs({ + @NamedEntityGraph( + name = "graph.RoomCriteriasDaylight.fulldetails", + attributeNodes = { + @NamedAttributeNode("property"), + @NamedAttributeNode("room"), + @NamedAttributeNode("channels"), + @NamedAttributeNode("roomType") + } + ) +}) +public class CfgRoomCriteriasDaylightView implements Serializable { + + @Id + @Column(name = "id") + private Long id; + @Column(name = "property_id") + private Long propertyId; + + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + @Column(name = "book_date") + private LocalDateTime bookDate; + + @Column(name = "room_id") + private Long roomId; + + @Column(name = "created_at") + private LocalDateTime createdAt; + + @Column(name = "created_by") + private String createdBy; + + @Column(name = "updated_at") + private LocalDateTime updatedAt; + + @Column(name = "updated_by") + private String updatedBy; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "property_id", insertable = false, updatable = false) + private CfgProperties property; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "room_id", insertable = false, updatable = false) + private CfgRooms room; + + @Column(name = "is_waitlist") + private Integer isWaitlist; + + @Column(name = "sharer") + private Integer sharer; + + @Transient + private List blockCodeChannels; + + //@NotFound(action = NotFoundAction.IGNORE) + @OneToMany(fetch = FetchType.EAGER) + @JoinColumn(name = "criteria_id", insertable = false, updatable = false) + private Set channels; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name = "cfg_rooms_room_types", joinColumns = {@JoinColumn(name = "room_id")}, inverseJoinColumns = {@JoinColumn(name = "room_type_id")}) + private Set roomType; + + @Column(name = "rate") + private Integer rate; + + @Column(name = "dow") + private Integer bookDow; + + //-- Attribute for export + @Transient + private String propertyName; + @Transient + private String bookDateText; + @Transient + private String bookWeekDay; + @Transient + private String roomCategory; + @Transient + private String roomTypeNames; + @Transient + private List channelList; + @Transient + private String rateValue; + @Transient + private String sharerValue; + @Transient + private String waitListValue; +} diff --git a/src/main/java/com/mgm/mcrm/allotment/repositories/AppChannelDao.java b/src/main/java/com/mgm/mcrm/allotment/repositories/AppChannelDao.java new file mode 100644 index 0000000..884653f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/allotment/repositories/AppChannelDao.java @@ -0,0 +1,13 @@ +package com.mgm.mcrm.allotment.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import com.mgm.mcrm.allotment.models.CfgAppChannel; + + +public interface AppChannelDao extends JpaRepository { + +} diff --git a/src/main/java/com/mgm/mcrm/allotment/repositories/OtherAllotmentDao.java b/src/main/java/com/mgm/mcrm/allotment/repositories/OtherAllotmentDao.java new file mode 100644 index 0000000..4ea2e46 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/allotment/repositories/OtherAllotmentDao.java @@ -0,0 +1,24 @@ +package com.mgm.mcrm.allotment.repositories; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import com.mgm.mcrm.allotment.models.CfgOtherAllotment; + + + +public interface OtherAllotmentDao extends JpaRepository { + CfgOtherAllotment findById(long id); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + List findByRoomIdInAndPropertyIdAndBookDateBetween(List roomId, Long propertyId,Date startDate, Date endDate); + +} diff --git a/src/main/java/com/mgm/mcrm/allotment/repositories/OtherAllotmentViewDao.java b/src/main/java/com/mgm/mcrm/allotment/repositories/OtherAllotmentViewDao.java new file mode 100644 index 0000000..36302e7 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/allotment/repositories/OtherAllotmentViewDao.java @@ -0,0 +1,28 @@ +package com.mgm.mcrm.allotment.repositories; + +import java.util.Date; +import java.util.List; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; +import com.mgm.mcrm.allotment.models.CfgOtherAllotmentView; + +public interface OtherAllotmentViewDao extends JpaRepository { + @EntityGraph(value = "graph.OtherAllotment.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findAll(Specification spec,Sort sort); + + @EntityGraph(value = "graph.OtherAllotment.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findAll(Specification spec); + + Page findAll(Specification spec, Pageable pageable); + + @EntityGraph(value = "graph.OtherAllotment.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findByRoomIdInAndPropertyIdAndBookDateBetween(List roomId, Long propertyId,Date startDate, Date endDate); + + @EntityGraph(value = "graph.OtherAllotment.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + CfgOtherAllotmentView findById(long id); + +} diff --git a/src/main/java/com/mgm/mcrm/allotment/repositories/RoomCriteriaDao.java b/src/main/java/com/mgm/mcrm/allotment/repositories/RoomCriteriaDao.java new file mode 100644 index 0000000..9689403 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/allotment/repositories/RoomCriteriaDao.java @@ -0,0 +1,33 @@ +package com.mgm.mcrm.allotment.repositories; + +import java.util.Date; +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import com.mgm.mcrm.allotment.models.CfgRoomCriterias; + + + +public interface RoomCriteriaDao extends JpaRepository { + CfgRoomCriterias findById(long id); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + List findByRoomIdInAndPropertyIdAndBookDateBetween(List roomId, Long propertyId,Date startDate, Date endDate); + List findByRoomIdNotInAndPropertyIdAndBookDateBetween(List roomIds, Long propertyId, + Date checkinDate, Date checkoutDate); + + @Transactional + @Modifying + @Query(value = " delete from cfg_room_criterias where id=?1 ",nativeQuery=true) + int deleteById(long id); + +} diff --git a/src/main/java/com/mgm/mcrm/allotment/repositories/RoomCriteriaDaylightDao.java b/src/main/java/com/mgm/mcrm/allotment/repositories/RoomCriteriaDaylightDao.java new file mode 100644 index 0000000..7afa4b8 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/allotment/repositories/RoomCriteriaDaylightDao.java @@ -0,0 +1,56 @@ +package com.mgm.mcrm.allotment.repositories; + +import com.mgm.mcrm.allotment.models.CfgRoomCriteriasDaylight; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.List; + + +public interface RoomCriteriaDaylightDao extends JpaRepository { + CfgRoomCriteriasDaylight findById(long id); + + List findAll(Specification spec, Sort sort); + + List findAll(Specification spec); + + Page findAll(Specification spec, Pageable pageable); + + List findByPropertyId(Long propertyId); + + List findByBookDateBetween(LocalDateTime startDate, LocalDateTime endDate); + + List findByRoomIdIn(List roomIds); + + List findByPropertyIdAndBookDateBetween(Long propertyId, LocalDateTime startDate, LocalDateTime endDate); + + List findByRoomIdInAndBookDateBetween(List roomId, LocalDateTime startDate, LocalDateTime endDate); + + List findByRoomIdInAndPropertyId(List roomId, Long propertyId); + + List findByRoomIdInAndPropertyIdAndBookDateBetween(List roomId, Long propertyId, LocalDateTime startDate, LocalDateTime endDate); + + List findByRoomIdNotInAndPropertyIdAndBookDateBetween(List roomIds, Long propertyId, + LocalDateTime checkinDate, LocalDateTime checkoutDate); + + List findByRoomIdAndPropertyIdAndBookDate(Long roomId, Long propertyId, LocalDateTime bookDate); + + @Transactional + @Modifying + @Query(value = " delete from cfg_room_criterias_daylight where id=?1 ", nativeQuery = true) + int deleteById(long id); + + @Query(value = "select * from cfg_room_criterias_daylight where id =?1", nativeQuery = true) + CfgRoomCriteriasDaylight getById(String loginId); + + @Query(value = "select count(1) from cfg_room_criterias_daylight where property_id=?1 and book_date=?2 and room_id =?3 ", nativeQuery = true) + int countByKeys(Long propertyId, LocalDateTime bookDate, Long roomId); + +} diff --git a/src/main/java/com/mgm/mcrm/allotment/repositories/RoomCriteriaDaylightViewDao.java b/src/main/java/com/mgm/mcrm/allotment/repositories/RoomCriteriaDaylightViewDao.java new file mode 100644 index 0000000..be084db --- /dev/null +++ b/src/main/java/com/mgm/mcrm/allotment/repositories/RoomCriteriaDaylightViewDao.java @@ -0,0 +1,53 @@ +package com.mgm.mcrm.allotment.repositories; + +import com.mgm.mcrm.allotment.models.CfgRoomCriteriasDaylightView; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.time.LocalDateTime; +import java.util.List; + +@Repository +public interface RoomCriteriaDaylightViewDao extends JpaRepository { + @EntityGraph(value = "graph.RoomCriteriasDaylight.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findAll(Specification spec, Sort sort); + + @EntityGraph(value = "graph.RoomCriteriasDaylight.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findAll(Specification spec); + + Page findAll(Specification spec, Pageable pageable); + + @EntityGraph(value = "graph.RoomCriteriasDaylight.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findByRoomIdInAndPropertyIdAndBookDateBetween(List roomId, Long propertyId,LocalDateTime startDate, LocalDateTime endDate); + + @EntityGraph(value = "graph.RoomCriteriasDaylight.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findByRoomIdNotInAndPropertyIdAndBookDateBetween(List roomIds, Long propertyId, + LocalDateTime checkinDate, LocalDateTime checkoutDate); + + @EntityGraph(value = "graph.RoomCriteriasDaylight.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findByPropertyId(Long propertyId); + + @EntityGraph(value = "graph.RoomCriteriasDaylight.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findByBookDateBetween(LocalDateTime startDate, LocalDateTime endDate); + + @EntityGraph(value = "graph.RoomCriteriasDaylight.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findByRoomIdIn(List roomId); + + @EntityGraph(value = "graph.RoomCriteriasDaylight.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findByPropertyIdAndBookDateBetween(Long propertyId, LocalDateTime startDate, LocalDateTime endDate); + + @EntityGraph(value = "graph.RoomCriteriasDaylight.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findByRoomIdInAndBookDateBetween(List roomId, LocalDateTime startDate, LocalDateTime endDate); + + @EntityGraph(value = "graph.RoomCriteriasDaylight.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findByRoomIdInAndPropertyId(List roomId, Long propertyId); + + @EntityGraph(value = "graph.RoomCriteriasDaylight.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + CfgRoomCriteriasDaylightView findById(long id); + +} diff --git a/src/main/java/com/mgm/mcrm/approval/controller/ApprovalController.java b/src/main/java/com/mgm/mcrm/approval/controller/ApprovalController.java new file mode 100644 index 0000000..afd5315 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/approval/controller/ApprovalController.java @@ -0,0 +1,154 @@ +package com.mgm.mcrm.approval.controller; + +import com.auth0.jwt.JWT; +import com.mgm.mcrm.approval.dtos.GetApproverRequest; +import com.mgm.mcrm.approval.dtos.RejectApprovalResponse; +import com.mgm.mcrm.approval.dtos.SubmitApprovalResponse; +import com.mgm.mcrm.approval.models.ApprovalDetail; +import com.mgm.mcrm.approval.models.CfgRequestReason; +import com.mgm.mcrm.approval.service.ApprovalService; +import com.mgm.mcrm.authorization.services.SysGroupPermissionService; +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.booking.models.BookingsView; +import com.mgm.mcrm.common.annotation.logging.OperationLog; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.common.dtos.mgm_api.ApproverResult; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import org.apache.commons.lang3.StringUtils; +import org.apache.coyote.Response; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/api") +public class ApprovalController { + + @Resource + private ApprovalService approvalService; + @Resource + private SysGroupPermissionService sysGroupPermissionService; + + + @OperationLog(actionName = "Cancel Approval Booking", eventCode = "approval_booking_cancel") + @RequestMapping(value = "/app/approval/cancel_approval", method = RequestMethod.POST, produces = "application/json;charset=UTF-8",consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity> cancelApprovalBooking(HttpServletRequest request, @RequestBody Map booking) { + + String token = request.getHeader("Authorization"); + String userId = JWT.decode(token).getClaim("login_id").asString(); + BaseApiResponse result = approvalService.cancelApprovalBooking(booking, userId, request); + + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @OperationLog(actionName = "Cancel Approval Booking", eventCode = "approval_booking_cancel") + @RequestMapping(value = "/app/approval/batch_cancel_approval", method = RequestMethod.POST, produces = "application/json;charset=UTF-8",consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity> batchCancelApproval(HttpServletRequest request, @RequestBody Map booking) { + + String token = request.getHeader("Authorization"); + + if (StringUtils.isNotBlank(token)) { + token = token.replace("Bearer ", "").replace("bearer ", ""); + } + + String userId = JWT.decode(token).getClaim("login_id").asString(); + BaseApiResponse result = approvalService.batchCancelApprovalBooking(booking, userId, request); + + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @OperationLog(actionName = "Get Approval Reason", eventCode = "get_approval_reason") + @RequestMapping(value = "/app/approval/get_reason", method = RequestMethod.POST, produces = "application/json;charset=UTF-8",consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity>> getApprovalReason(HttpServletRequest request, @RequestBody Map booking) throws Exception { + BaseApiResponse> result = approvalService.getRequestReason(); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @OperationLog(actionName = "Get Approver", eventCode = "get_approver") + @RequestMapping(value = "/app/approval/get_approver", method = RequestMethod.POST, produces = "application/json;charset=UTF-8",consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity> getESBApprover(HttpServletRequest request, @RequestBody GetApproverRequest params) throws Exception { + BaseApiResponse result = approvalService.getApprover(request, params); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @PostMapping(value="/app/approval/approval_list",consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity>> getPendingApprovalBookingList(HttpServletRequest request, @RequestBody Map params) throws Exception { + BaseApiResponse> pendingApprovalList = approvalService.getPendingApprovalList(request,params); + return ResponseEntity.status(HttpStatus.OK).body(pendingApprovalList); + } + + @PostMapping("/app/approval/get_approval_count") + public ResponseEntity> getPendingApprovalCount(HttpServletRequest request) { + BaseApiResponse result = approvalService.getCountPendingApproval(request); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @PostMapping(value="/app/approval/reject_approval",consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity> rejectApprovalRecord(HttpServletRequest request, @RequestBody Map params) throws Exception { + String token = request.getHeader("Authorization"); + String userId = JWT.decode(token).getClaim("login_id").asString(); + Long bookingId = params.get("bookingId") == null ? null : Long.valueOf(params.get("bookingId").toString()); + BaseApiResponse result = approvalService.rejectApprovalBooking(bookingId, userId); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @PostMapping(value="/app/approval/get_approval_data",consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity> getApprovalData(HttpServletRequest request, @RequestBody Map params) throws Exception { + BaseApiResponse result = approvalService.getApprovalDetail(request, params); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @PostMapping(value="/app/approval/submit_approval",consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity> submitApproval(HttpServletRequest request, @RequestBody Map params) throws Exception { + String token = request.getHeader("Authorization"); + String userId = JWT.decode(token).getClaim("login_id").asString(); + String checkinDate = params.get("checkinDate") == null ? null : params.get("checkinDate").toString(); + String checkoutDate = params.get("checkoutDate") == null ? null : params.get("checkoutDate").toString(); + String bookingId = params.get("bookingId") == null ? null : params.get("bookingId").toString(); + BaseApiResponse serviceResult = new BaseApiResponse<>(); + try{ + serviceResult = approvalService.submitApproval(bookingId, checkinDate, checkoutDate, userId,request); + } catch (Exception e) { + approvalService.setFailApprovalRouting(bookingId); + throw new RuntimeException(e); + } + return ResponseEntity.status(HttpStatus.OK).body(serviceResult); + } + + @PostMapping(value="/app/approval/batch_submit_approval",consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity>>> batchApproveBooking(HttpServletRequest request, @RequestBody Map params) throws Exception { + BaseApiResponse>> result = approvalService.batchApproval(request, params); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @PostMapping(value="/app/approval/batch_submit_reject",consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity>> batchRejectApproval(HttpServletRequest request, @RequestBody Map params) throws Exception { + + String token = request.getHeader("Authorization"); + String userId = JWT.decode(token).getClaim("login_id").asString(); + // 修改这里:从 submitInfoList 获取数据 + @SuppressWarnings("unchecked") + List> submitInfoList = params.get("submitInfoList") != null + ? (List>) params.get("submitInfoList") + : null; + + + BaseApiResponse> serviceResult = new BaseApiResponse<>(); + if (submitInfoList != null && !submitInfoList.isEmpty()) { + // 提取 bookingId 列表 + List bookingIdList = submitInfoList.stream() + .map(item -> String.valueOf(item.get("bookingId"))) + .collect(Collectors.toList()); + + serviceResult = approvalService.batchReject(bookingIdList, userId); + } + return ResponseEntity.status(HttpStatus.OK).body(serviceResult); + } +} diff --git a/src/main/java/com/mgm/mcrm/approval/dtos/GetApproverRequest.java b/src/main/java/com/mgm/mcrm/approval/dtos/GetApproverRequest.java new file mode 100644 index 0000000..943f982 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/approval/dtos/GetApproverRequest.java @@ -0,0 +1,13 @@ +package com.mgm.mcrm.approval.dtos; + +import lombok.Data; + +@Data +public class GetApproverRequest { + private String playerId; + private String bookingType; + private String propertyName; + private String roomCategory; + private String checkInDate; + private String checkOutDate; +} diff --git a/src/main/java/com/mgm/mcrm/approval/dtos/RejectApprovalResponse.java b/src/main/java/com/mgm/mcrm/approval/dtos/RejectApprovalResponse.java new file mode 100644 index 0000000..8c22be9 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/approval/dtos/RejectApprovalResponse.java @@ -0,0 +1,14 @@ +package com.mgm.mcrm.approval.dtos; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * API response returned after an approval is rejected. + */ +@Getter +@AllArgsConstructor +public class RejectApprovalResponse { + + private final Long bookingId; +} diff --git a/src/main/java/com/mgm/mcrm/approval/dtos/SubmitApprovalResponse.java b/src/main/java/com/mgm/mcrm/approval/dtos/SubmitApprovalResponse.java new file mode 100644 index 0000000..dd23f88 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/approval/dtos/SubmitApprovalResponse.java @@ -0,0 +1,17 @@ +package com.mgm.mcrm.approval.dtos; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * API response returned after an approval is submitted. + * + *

The API exposes only the identifier clients need and does not leak the + * Hibernate-managed {@code Bookings} entity.

+ */ +@Getter +@AllArgsConstructor +public class SubmitApprovalResponse { + + private final Long bookingId; +} diff --git a/src/main/java/com/mgm/mcrm/approval/mappers/ApprovalMapper.java b/src/main/java/com/mgm/mcrm/approval/mappers/ApprovalMapper.java new file mode 100644 index 0000000..d7a1186 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/approval/mappers/ApprovalMapper.java @@ -0,0 +1,26 @@ +package com.mgm.mcrm.approval.mappers; + +import com.mgm.mcrm.approval.dtos.RejectApprovalResponse; +import com.mgm.mcrm.approval.dtos.SubmitApprovalResponse; +import com.mgm.mcrm.booking.models.Bookings; +import org.springframework.stereotype.Component; + +@Component +public class ApprovalMapper { + + public SubmitApprovalResponse toSubmitApprovalResponse(Bookings booking) { + if (booking == null) { + return null; + } + + return new SubmitApprovalResponse(booking.getId()); + } + + public RejectApprovalResponse toRejectApprovalResponse(Bookings booking) { + if (booking == null) { + return null; + } + + return new RejectApprovalResponse(booking.getId()); + } +} diff --git a/src/main/java/com/mgm/mcrm/approval/models/ApprovalDetail.java b/src/main/java/com/mgm/mcrm/approval/models/ApprovalDetail.java new file mode 100644 index 0000000..56092d7 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/approval/models/ApprovalDetail.java @@ -0,0 +1,57 @@ +package com.mgm.mcrm.approval.models; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.mgm.mcrm.booking.models.BookingsView; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * 审批详情返回:前端请使用 {@link #cfgApprovalRoutingList}(与 {@link #bookingsViewList} 顺序一致)。 + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ApprovalDetail implements Serializable { + + List bookingsViewList = new ArrayList(); + + List approvalGamingData = new ArrayList(); + + /** @deprecated 请使用 {@link #cfgApprovalRoutingList} */ + CfgApprovalRouting cfgApprovalRouting; + + /** 与 {@link #bookingsViewList} 顺序一致,每条 booking 对应一条审批路由 */ + List cfgApprovalRoutingList = new ArrayList(); + + public List getBookingsViewList() { + return bookingsViewList; + } + + public void setBookingsViewList(List bookingsViewgList) { + this.bookingsViewList = bookingsViewgList; + } + + public List getApprovalGamingData() { + return approvalGamingData; + } + + public void setApprovalGamingData(List approvalGamingData) { + this.approvalGamingData = approvalGamingData; + } + + public CfgApprovalRouting getCfgApprovalRouting() { + return cfgApprovalRouting; + } + + public void setCfgApprovalRouting(CfgApprovalRouting cfgApprovalRouting) { + this.cfgApprovalRouting = cfgApprovalRouting; + } + + public List getCfgApprovalRoutingList() { + return cfgApprovalRoutingList; + } + + public void setCfgApprovalRoutingList(List cfgApprovalRoutingList) { + this.cfgApprovalRoutingList = cfgApprovalRoutingList; + } +} diff --git a/src/main/java/com/mgm/mcrm/approval/models/ApprovalGamingData.java b/src/main/java/com/mgm/mcrm/approval/models/ApprovalGamingData.java new file mode 100644 index 0000000..1d6291c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/approval/models/ApprovalGamingData.java @@ -0,0 +1,160 @@ +package com.mgm.mcrm.approval.models; + +import com.alibaba.fastjson.annotation.JSONField; + +import java.io.Serializable; + + +public class ApprovalGamingData implements Serializable { + + @JSONField(name = "BookingId") + private String bookingId; + @JSONField(name = "PlayerId") + private String playerId; + @JSONField(name = "CurrentTripTheoWinAmount") + private String currentTripTheoWinAmount=null; + @JSONField(name = "Last2DayTheoWinAmount") + private String last2DayTheoWinAmount=null; + @JSONField(name = "R3TheoWin") + private String r3TheoWin=null; + @JSONField(name = "R3TPD") + private String r3TPD=null; + @JSONField(name = "R3ActualWin") + private String r3ActualWin=null; + @JSONField(name = "R6TheoWin") + private String r6TheoWin=null; + @JSONField(name = "R6TPD") + private String r6TPD=null; + @JSONField(name = "R6ActualWin") + private String r6ActualWin=null; + @JSONField(name = "R12TheoWin") + private String r12TheoWin=null; + @JSONField(name = "R12TPD") + private String r12TPD=null; + @JSONField(name = "R12ActualWin") + private String r12ActualWin=null; + @JSONField(name = "OverlapBooking") + private String overlapBooking=null; + @JSONField(name = "RoomCount") + private String roomCount=null; + + public String getBookingId() { + return bookingId; + } + + public void setBookingId(String bookingId) { + this.bookingId = bookingId; + } + + public String getPlayerId() { + return playerId; + } + + public void setPlayerId(String playerId) { + this.playerId = playerId; + } + + public String getCurrentTripTheoWinAmount() { + return currentTripTheoWinAmount; + } + + public void setCurrentTripTheoWinAmount(String currentTripTheoWinAmount) { + this.currentTripTheoWinAmount = currentTripTheoWinAmount; + } + + public String getLast2DayTheoWinAmount() { + return last2DayTheoWinAmount; + } + + public void setLast2DayTheoWinAmount(String last2DayTheoWinAmount) { + this.last2DayTheoWinAmount = last2DayTheoWinAmount; + } + + public String getR3TheoWin() { + return r3TheoWin; + } + + public void setR3TheoWin(String r3TheoWin) { + this.r3TheoWin = r3TheoWin; + } + + public String getR3TPD() { + return r3TPD; + } + + public void setR3TPD(String r3TPD) { + this.r3TPD = r3TPD; + } + + public String getR3ActualWin() { + return r3ActualWin; + } + + public void setR3ActualWin(String r3ActualWin) { + this.r3ActualWin = r3ActualWin; + } + + public String getR6TheoWin() { + return r6TheoWin; + } + + public void setR6TheoWin(String r6TheoWin) { + this.r6TheoWin = r6TheoWin; + } + + public String getR6TPD() { + return r6TPD; + } + + public void setR6TPD(String r6TPD) { + this.r6TPD = r6TPD; + } + + public String getR6ActualWin() { + return r6ActualWin; + } + + public void setR6ActualWin(String r6ActualWin) { + this.r6ActualWin = r6ActualWin; + } + + public String getR12TheoWin() { + return r12TheoWin; + } + + public void setR12TheoWin(String r12TheoWin) { + this.r12TheoWin = r12TheoWin; + } + + public String getR12TPD() { + return r12TPD; + } + + public void setR12TPD(String r12TPD) { + this.r12TPD = r12TPD; + } + + public String getR12ActualWin() { + return r12ActualWin; + } + + public void setR12ActualWin(String r12ActualWin) { + this.r12ActualWin = r12ActualWin; + } + + public String getOverlapBooking() { + return overlapBooking; + } + + public void setOverlapBooking(String overlapBooking) { + this.overlapBooking = overlapBooking; + } + + public String getRoomCount() { + return roomCount; + } + + public void setRoomCount(String roomCount) { + this.roomCount = roomCount; + } +} diff --git a/src/main/java/com/mgm/mcrm/approval/models/CfgApprovalRouting.java b/src/main/java/com/mgm/mcrm/approval/models/CfgApprovalRouting.java new file mode 100644 index 0000000..9dc38f4 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/approval/models/CfgApprovalRouting.java @@ -0,0 +1,137 @@ +package com.mgm.mcrm.approval.models; + +import jakarta.persistence.*; + +import java.io.Serializable; +import java.util.Date; + +@Entity +@Table(name="cfg_approval_routing") +public class CfgApprovalRouting implements Serializable { + //fields in table + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="booking_id") + private Long bookingId; + @Column(name="approval_reason") + private String approvalReason; + @Column(name="approver_id") + private String approverId; + @Column(name="approver_name") + private String approverName; + @Column(name="booking_status") + private String bookingStatus; + @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="routing_reason") + private String routingReason; + + @Version + @Column(name = "version") + private Long version; + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getBookingId() { + return bookingId; + } + + public void setBookingId(Long bookingId) { + this.bookingId = bookingId; + } + + public String getApprovalReason() { + return approvalReason; + } + + public void setApprovalReason(String approvalReason) { + this.approvalReason = approvalReason; + } + + public String getApproverId() { + return approverId; + } + + public void setApproverId(String approverId) { + this.approverId = approverId; + } + + public String getApproverName() { + return approverName; + } + + public void setApproverName(String approverName) { + this.approverName = approverName; + } + + public String getBookingStatus() { + return bookingStatus; + } + + public void setBookingStatus(String bookingStatus) { + this.bookingStatus = bookingStatus; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + public String getRoutingReason() { + return routingReason; + } + + public void setRoutingReason(String routingReason) { + this.routingReason = routingReason; + } + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } +} diff --git a/src/main/java/com/mgm/mcrm/approval/models/CfgRequestReason.java b/src/main/java/com/mgm/mcrm/approval/models/CfgRequestReason.java new file mode 100644 index 0000000..2c0b214 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/approval/models/CfgRequestReason.java @@ -0,0 +1,94 @@ +package com.mgm.mcrm.approval.models; + +import jakarta.persistence.*; + +import java.io.Serializable; +import java.util.Date; + +@Entity +@Table(name="cfg_request_reason") +public class CfgRequestReason implements Serializable { + //fields in table + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="description") + private String description; + @Column(name="code") + private String code; + @Column(name="is_show") + private int isShow; + @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; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public int getIsShow() { + return isShow; + } + + public void setIsShow(int isShow) { + this.isShow = isShow; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } +} diff --git a/src/main/java/com/mgm/mcrm/approval/repositories/ApprovalRoutingDao.java b/src/main/java/com/mgm/mcrm/approval/repositories/ApprovalRoutingDao.java new file mode 100644 index 0000000..de04410 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/approval/repositories/ApprovalRoutingDao.java @@ -0,0 +1,52 @@ +package com.mgm.mcrm.approval.repositories; + +import com.mgm.mcrm.approval.models.CfgApprovalRouting; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + + +public interface ApprovalRoutingDao extends JpaRepository { + CfgApprovalRouting findById(long id); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + + @Transactional + @Modifying + @Query(value = " delete from cfg_approval_routing where id=?1 ",nativeQuery=true) + int deleteById(long id); + + @Query(value="select * from cfg_approval_routing where id =?1",nativeQuery=true) + CfgApprovalRouting getById(Long id); + + @Query(value="select * from cfg_approval_routing where id =?1",nativeQuery=true) + CfgApprovalRouting getById(Integer id); + + @Query(value="select * from cfg_approval_routing where name =?1",nativeQuery=true) + CfgApprovalRouting getByName(String name); + + + List findByBookingStatus(String bookingStatus); + + Integer countByBookingStatus(String bookingStatus); + + Integer countByBookingStatusAndApproverId(String bookingStatus, String approverId); + + CfgApprovalRouting getByBookingId(Long bookingId); + + List findByBookingStatusAndApproverId(String ap, String userId); + + @Query(value = "select * from cfg_approval_routing where booking_status = 'AP' and approver_id like concat('%', ?1, '%')", nativeQuery = true) + List getApprovalList(String userId); + + @Query(value = "select count(*) from cfg_approval_routing where booking_status = 'AP' and approver_id like concat('%', ?1, '%')", nativeQuery = true) + Long countApprovalList(String userId); +} diff --git a/src/main/java/com/mgm/mcrm/approval/repositories/RequestReasonDao.java b/src/main/java/com/mgm/mcrm/approval/repositories/RequestReasonDao.java new file mode 100644 index 0000000..04ab0aa --- /dev/null +++ b/src/main/java/com/mgm/mcrm/approval/repositories/RequestReasonDao.java @@ -0,0 +1,37 @@ +package com.mgm.mcrm.approval.repositories; + +import com.mgm.mcrm.approval.models.CfgRequestReason; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + + +public interface RequestReasonDao extends JpaRepository { + CfgRequestReason findById(long id); + List findAll(Specification spec, Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + CfgRequestReason findByCode(String code); + + @Transactional + @Modifying + @Query(value = " delete from cfg_request_reason where id=?1 ",nativeQuery=true) + int deleteById(long id); + + @Query(value="select * from cfg_request_reason where id =?1",nativeQuery=true) + CfgRequestReason getById(Long id); + + @Query(value="select * from cfg_request_reason where id =?1",nativeQuery=true) + CfgRequestReason getById(Integer id); + + + + CfgRequestReason getByCode(String code); +} diff --git a/src/main/java/com/mgm/mcrm/approval/service/ApprovalService.java b/src/main/java/com/mgm/mcrm/approval/service/ApprovalService.java new file mode 100644 index 0000000..2316505 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/approval/service/ApprovalService.java @@ -0,0 +1,1414 @@ +package com.mgm.mcrm.approval.service; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.parser.Feature; +import com.auth0.jwt.JWT; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.mgm.mcrm.allotment.models.CfgAppChannel; +import com.mgm.mcrm.allotment.models.CfgOtherAllotment; +import com.mgm.mcrm.allotment.models.CfgOtherAppChannel; +import com.mgm.mcrm.allotment.models.CfgRoomCriterias; +import com.mgm.mcrm.allotment.repositories.OtherAllotmentDao; +import com.mgm.mcrm.allotment.repositories.RoomCriteriaDao; +import com.mgm.mcrm.approval.dtos.GetApproverRequest; +import com.mgm.mcrm.approval.dtos.RejectApprovalResponse; +import com.mgm.mcrm.approval.dtos.SubmitApprovalResponse; +import com.mgm.mcrm.approval.mappers.ApprovalMapper; +import com.mgm.mcrm.approval.models.ApprovalDetail; +import com.mgm.mcrm.approval.models.ApprovalGamingData; +import com.mgm.mcrm.approval.models.CfgApprovalRouting; +import com.mgm.mcrm.approval.models.CfgRequestReason; +import com.mgm.mcrm.approval.repositories.ApprovalRoutingDao; +import com.mgm.mcrm.approval.repositories.RequestReasonDao; +import com.mgm.mcrm.appsetting.models.CfgSettings; +import com.mgm.mcrm.appsetting.services.SettingService; +import com.mgm.mcrm.appsetting.services.SysSettingService; +import com.mgm.mcrm.authorization.dtos.LoginUserInfo; +import com.mgm.mcrm.authorization.services.MgmUserService; +import com.mgm.mcrm.authorization.services.SysGroupPermissionService; +import com.mgm.mcrm.basesetting.property.models.CfgProperties; +import com.mgm.mcrm.basesetting.property.repositories.PropertyDao; +import com.mgm.mcrm.basesetting.room.models.CfgOtherRoomStatus; +import com.mgm.mcrm.basesetting.room.repositories.OtherRoomStatusDao; +import com.mgm.mcrm.basesetting.team.repositories.TeamStructureDao; +import com.mgm.mcrm.booking.dtos.BookingDto; +import com.mgm.mcrm.booking.mappers.BookingMapper; +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.booking.models.BookingsView; +import com.mgm.mcrm.booking.repositories.BookingDao; +import com.mgm.mcrm.booking.repositories.BookingViewDao; +import com.mgm.mcrm.booking.services.BookingService; +import com.mgm.mcrm.booking.services.NonMGMBookingService; +import com.mgm.mcrm.booking.services.OperaDBBookingService; +import com.mgm.mcrm.booking.services.OperaService; +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.constants.SysConstants; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.common.dtos.EumnApprovalStatus; +import com.mgm.mcrm.common.dtos.http_util.HttpResponseResult; +import com.mgm.mcrm.common.dtos.mgm_api.*; +import com.mgm.mcrm.common.jms.BookingControlMsgSender; +import com.mgm.mcrm.common.services.MGMApiService; +import com.mgm.mcrm.common.utils.DateTimeUtil; +import com.mgm.mcrm.common.utils.LogUtil; +import com.mgm.mcrm.common.utils.SendEmail; +import com.mgm.mcrm.logging.models.SysLogBooking; +import com.mgm.mcrm.logging.repositories.SysLogBookingDao; +import com.mgm.mcrm.logging.services.SysLogBookingService; +import com.mgm.mcrm.notification.models.Email; +import com.mgm.mcrm.notification.repositories.EmailDao; +import com.mgm.mcrm.player.services.PlayerService; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.hibernate.StaleObjectStateException; +import org.slf4j.Logger; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.RequestBody; + +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; +import java.util.*; +import java.util.stream.Collectors; + +@Service +public class ApprovalService { + + @Resource + private SysSettingService sysSettingService; + @Resource + private BookingViewDao bookingViewDao; + @Resource + private BookingDao bookingDao ; + @Resource + private SysLogBookingService sysLogBookingService ; + @Resource + private RequestReasonDao requestReasonDao; + @Resource + private MGMApiService mgmApiService; + @Resource + private PropertyDao propertyDao; + @Resource + private OtherRoomStatusDao roomStatusDao; + @Resource + private OperaService operaService; + @Resource + private SysLogBookingDao sysLogBookingDao; + @Resource + private OperaDBBookingService operaDBBookingService; + @Resource + private SysGroupPermissionService sysGroupPermissionService; + @Resource + private BookingMapper bookingMapper; + @Resource + private ApprovalMapper approvalMapper; + + private final Logger log = LogUtil.getLogger(ApprovalService.class); + @Autowired + private ApprovalRoutingDao approvalRoutingDao; + @Autowired + private BookingControlMsgSender ctrlMsgSender; + + + @Lazy + @Autowired + private BookingService bookingService; + @Autowired + private EmailDao emailDao; + @Autowired + private MgmUserService mgmUserService; + @Autowired + private SettingService settingService; + @Autowired + private PlayerService playerService; + @Autowired + private RoomCriteriaDao roomCriteriaDao; + @Autowired + private OtherRoomStatusDao otherRoomStatusDao; + @Autowired + private OtherAllotmentDao otherAllotmentDao; + /** 与 NonMGMBookingService 中的 ApprovalService 形成环,延迟注入打破循环 */ + @Lazy + @Autowired + private NonMGMBookingService nonMGMBookingService; + @Autowired + private TeamStructureDao teamStructureDao; + + public BaseApiResponse> getRequestReason() throws Exception { +// 新建對象 + BaseApiResponse> response = new BaseApiResponse>(); +// 獲取ApprovalReason + List requestReasons = requestReasonDao.findAll(); + if (!requestReasons.isEmpty()) { + response.setSuccess(true); + response.setData(requestReasons); + }else{ + response.setSuccess(false); + response.setMessage("No request reason found"); + } +// 返回數據 + return response; + } + + public BaseApiResponse getApprover(HttpServletRequest request, GetApproverRequest approvalRequest) throws Exception { + + + String playerId = approvalRequest.getPlayerId(); + String bookingType = approvalRequest.getBookingType(); + String propertyName =approvalRequest.getPropertyName(); + String roomCategory =approvalRequest.getRoomCategory(); + String checkInDate = approvalRequest.getCheckInDate(); + String checkOutDate =approvalRequest.getCheckOutDate(); + + String token = request.getHeader("Authorization"); + String userId = JWT.decode(token).getClaim("login_id").asString(); + + BaseApiResponse response = new BaseApiResponse<>(); + if(!StringUtils.isEmpty(userId)) { + userId = StringUtils.replace(userId, "@mgm.mo", ""); + } + if (propertyName == null && roomCategory == null) { + response.setSuccess(false); + response.setMessage("Missing required parameter 'propertyName' or 'roomCategory'"); + return response; + } + + try { + HttpResponseResult httpResult = mgmApiService.invokeGetApprover(playerId,bookingType,propertyName,roomCategory,checkInDate,checkOutDate,userId); + try { + ApproverResult resultObj = JSONObject.parseObject(httpResult.getResponseContent(), ApproverResult.class, Feature.SupportNonPublicField,Feature.IgnoreNotMatch); + if(Strings.CS.equals(resultObj.getStatusCode(), "OK")) { + if (resultObj.getRecords() != null && !resultObj.getRecords().isEmpty()) { + response.setSuccess(true); + // 只返回 Records[0] + response.setData(resultObj); + } else { + response.setSuccess(false); + response.setMessage("NO_RECORDS"); + LogUtil.info(ApprovalService.class, "[GetApprover Error] Records is empty"); + } + }else { + response.setSuccess(false); + response.setMessage(resultObj.getStatusDescription()); + LogUtil.info(ApprovalService.class, "[GetApprover Error]" + resultObj.getStatusDescription()); + + } + }catch(Exception err) { + response.setSuccess(false); + response.setMessage("RETURN_DATA_ERROR"); + LogUtil.info(ApprovalService.class, "[GetApprover Error]" + err.getMessage()); + } + + }catch(Exception err) { + response.setSuccess(false); + response.setMessage("INVOKE_GETAPPROVER_API_ERROR"); + LogUtil.info(ApprovalService.class, "[GetApprover Error]" + err.getMessage()); + } + + return response; + } + + public BaseApiResponse getApprovalData(String bookingId) throws Exception { + BaseApiResponse response = new BaseApiResponse<>(); + ApprovalGamingDataResult approvalGamingData = new ApprovalGamingDataResult(); + try { + HttpResponseResult httpResult = mgmApiService.invokeGetApprovalData(bookingId); + try { + approvalGamingData = JSONObject.parseObject(httpResult.getResponseContent(), ApprovalGamingDataResult.class, Feature.SupportNonPublicField,Feature.IgnoreNotMatch); + if(StringUtils.equalsIgnoreCase(approvalGamingData.getStatusCode(),"OK")) { + response.setData(approvalGamingData); + response.setSuccess(true); + return response; + }else { + response.setSuccess(false); + response.setMessage(approvalGamingData.getStatusDescription()); + LogUtil.info(ApprovalService.class, "[Get ApprovalData Error]" + approvalGamingData.getStatusDescription()); + + } + }catch(Exception err) { + response.setSuccess(false); + response.setMessage("RETURN_DATA_ERROR"); + LogUtil.info(ApprovalService.class, "[Get ApprovalData Error]" + err.getMessage()); + } + + }catch(Exception err) { + response.setSuccess(false); + response.setMessage("Get Approval Data Error"); + LogUtil.info(ApprovalService.class, "[Get ApprovalData Error]" + err.getMessage()); + } + return response; + } + + public void createApprovalRouting(Bookings booking, String approverId, String approverName, String approvalReasonId, String routingReason) throws Exception{ +// 获取ApprovalReason + LogUtil.info(ApprovalService.class, "[createApprovalRouting] Booking Id :" + booking.getId()); + CfgRequestReason cfgRequestReason = requestReasonDao.getById(Long.valueOf(approvalReasonId)); + Date now = new Date(); + //将 ApprovalRouting 数据插入表中 + CfgApprovalRouting newRouting = new CfgApprovalRouting(); + newRouting.setBookingId(booking.getId()); + newRouting.setApproverId(approverId); + newRouting.setApproverName(approverName); + newRouting.setApprovalReason(cfgRequestReason.getCode()); + newRouting.setCreatedAt(now); + newRouting.setUpdatedAt(now); + newRouting.setBookingStatus("AP"); + newRouting.setRoutingReason(routingReason); + newRouting.setCreatedBy(booking.getCreatedByName()); + newRouting.setUpdatedBy(null); + + booking.setApprovalReason(cfgRequestReason.getCode()); + bookingDao.save(booking); + + CfgApprovalRouting saveRouting = approvalRoutingDao.save(newRouting); + } + + public List getSearchRecordPendingApproval(String checkinDate, + String checkoutDate, String playerId) { + // 获得配置的过期分钟 暂无 +// AppSetting approvalExpMin = appSettingRepository.getByKeys(SettingConstants.APPROVAL_EXPIRE_MINUTES); +// if (approvalExpMin != null && StringUtils.isNotBlank(approvalExpMin.getKeyValues())) { +// expMin = Integer.valueOf(approvalExpMin.getKeyValues()); +// } + Boolean isMock = sysSettingService.isAPPMock(); + int expMin = 20000; + expMin = expMin * -1; + + Date dtNow = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + dtNow = DateTimeUtil.addMin(dtNow, expMin); + String nowStr = DateTimeUtil.getDateByFormat(dtNow, "yyyy-MM-dd HH:mm:ss"); + List bookingsViews = bookingViewDao.findRecordSearchPendingApproval(playerId, checkinDate, + checkoutDate, nowStr); + List newResult = new ArrayList<>(); + SimpleDateFormat dateOnlyFormat = new SimpleDateFormat("yyyy-MM-dd"); + dateOnlyFormat.setTimeZone(TimeZone.getTimeZone("GMT+8")); + Date now = new Date(); + + for (BookingsView booking : bookingsViews) { + if (booking.getCheckinDate() != null) { + LocalDate today = LocalDate.parse(dateOnlyFormat.format(now)); + LocalDate checkinDateOnly = + LocalDate.parse(dateOnlyFormat.format(booking.getCheckinDate())); + } + newResult.add(booking); + } + + + return bookingMapper.viewToBookingDtoList(newResult); + } + + public boolean isExpiredPendingApprovalBooking(BookingsView booking){ + SimpleDateFormat dateOnlyFormat = new SimpleDateFormat("yyyy-MM-dd"); + dateOnlyFormat.setTimeZone(TimeZone.getTimeZone("GMT+8")); + CfgSettings cutoffStartTime = settingService.getSettingByKey("VIEW_YESTERDAY_TODOLIST_START"); + CfgSettings cutoffEndTime = settingService.getSettingByKey("VIEW_YESTERDAY_TODOLIST_END"); + String cutoffStartTimeValue = cutoffStartTime != null ? cutoffStartTime.getKeyValues() : null; + String cutoffEndTimeValue = cutoffEndTime != null ? cutoffEndTime.getKeyValues() : null; + Date now = new Date(); + boolean isExpired = false; + + if (booking.getCheckinDate() != null) { + LocalDate today = LocalDate.parse(dateOnlyFormat.format(now)); + LocalDate checkinDateOnly = + LocalDate.parse(dateOnlyFormat.format(booking.getCheckinDate())); + // 已超过入住日(不含当天),且当前时间不在配置的 HH:mm 窗口内 → AE + if (checkinDateOnly.isBefore(today) + && !isCurrentTimeWithinCutoffWindowGmt8(cutoffStartTimeValue, cutoffEndTimeValue)) { + Bookings entity = bookingDao.getById(booking.getId()); + if (entity != null) { + entity.setApproveStatus("AE"); + entity.setUpdatedAt(now); + bookingDao.save(entity); + + CfgApprovalRouting approvalRouting = approvalRoutingDao.getByBookingId(entity.getId()); + if (approvalRouting != null) { + approvalRouting.setBookingStatus("AE"); + approvalRouting.setUpdatedAt(now); + approvalRoutingDao.save(approvalRouting); + } + isExpired = true; + } + } + } + return isExpired; + } + + /** + * 判断当前时间(GMT+8)是否在 [start, end] 内(含起止),配置为 HH:mm(如 09:30)。 + * 约定 start 不晚于 end;配置缺失或解析失败时返回 false(视为不在窗口内)。 + */ + private boolean isCurrentTimeWithinCutoffWindowGmt8(String startValue, String endValue) { + if (StringUtils.isBlank(startValue) || StringUtils.isBlank(endValue)) { + return false; + } + // 注意:Java 里分钟必须用小写 m;大写 M 表示「月份」。HH = 两位小时,H = 一位或两位小时 + DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH:mm"); + try { + LocalTime start = LocalTime.parse(startValue.trim(), fmt); + LocalTime end = LocalTime.parse(endValue.trim(), fmt); + ZoneId zone = ZoneId.of("GMT+8"); + LocalTime current = ZonedDateTime.now(zone).toLocalTime(); + return !current.isBefore(start) && !current.isAfter(end); + } catch (DateTimeParseException e) { + return false; + } + } + + + public BaseApiResponse cancelApprovalBooking(Map param,String userId, HttpServletRequest request) { + BaseApiResponse response = new BaseApiResponse<>(); + Date createDate = new Date(); + Bookings booking = new Bookings(); + Long bookId = Long.valueOf(String.valueOf(param.get("id"))); + ArrayList booksList = new ArrayList(); + booking = bookingDao.getById(bookId); + String status = booking.getApproveStatus(); + + if (Strings.CS.equals(booking.getCreatedBy(),userId)){ + if ("AP".equals(status)) { + booking.setApproveStatus("AC"); + booking.setUpdatedAt(createDate); + booking.setUpdatedBy(userId); + bookingDao.save(booking); + + response.setSuccess(true); + response.setData(bookId); + booksList.add(booking); + String oldStatus = EumnApprovalStatus.getApprovalStatusByDBValue(status); + String newStatus = EumnApprovalStatus.getApprovalStatusByDBValue("AC"); + sysLogBookingService.saveLogBooking(booksList, request,oldStatus,newStatus,"Cancel Approval Booking",""); + + + CfgApprovalRouting approvalRouting = approvalRoutingDao.getByBookingId(bookId); + approvalRouting.setBookingStatus("AC"); + approvalRouting.setUpdatedAt(createDate); + approvalRouting.setUpdatedBy(userId); + + approvalRoutingDao.save(approvalRouting); + + }else{ + response.setSuccess(false); + response.setLogMessage("BOOKING_STATUS_CHANGED"); + response.setMessage("Cannot Cancel Status is not Pending Approval Booking"); + } + }else{ + response.setSuccess(false); + response.setLogMessage("NO_AUTHORIZED"); + response.setMessage("You have not authorized to Cancel this Booking"); + return response; + } + + return response; + } + + public BaseApiResponse batchCancelApprovalBooking(Map param,String userId, HttpServletRequest request) { + BaseApiResponse response = new BaseApiResponse<>(); + Date createDate = new Date(); + Bookings booking = new Bookings(); + String[] bookIds = (String.valueOf(param.get("bookId"))).split(";"); + ArrayList booksList = new ArrayList(); + StringBuilder failId = new StringBuilder(); + for (String id : bookIds) { + booking = bookingDao.findById(Long.parseLong(id)).orElse(null); + String status = booking.getApproveStatus(); + if ("AP".equals(status)) { + + booking.setApproveStatus("AC"); + booking.setUpdatedAt(createDate); + booking.setUpdatedBy(userId); + bookingDao.save(booking); + + Date date = new Date(); + CfgApprovalRouting newRouting = approvalRoutingDao.getByBookingId(booking.getId()); + newRouting.setBookingStatus("AC"); + newRouting.setUpdatedAt(date); + newRouting.setUpdatedBy(userId); + approvalRoutingDao.save(newRouting); + + String oldStatus = EumnApprovalStatus.getApprovalStatusByDBValue(status); + String newStatus = EumnApprovalStatus.getApprovalStatusByDBValue("AC"); + sysLogBookingService.saveLogBooking(booksList, request,oldStatus,newStatus,"Cancel Approval Booking",""); + + response.setSuccess(true); + response.setData(booking); + booksList.add(booking); + }else{ + failId.append(id); + } + } + if (!failId.isEmpty()){ + response.setSuccess(false); + response.setMessage("Cancel Pending Approval Booking Fail,BookId : "+failId.toString()); + } + return response; + } + + public BaseApiResponse> getPendingApprovalList(HttpServletRequest request,Map params) throws Exception { + + String token = request.getHeader("Authorization"); + String userId = JWT.decode(token).getClaim("login_id").asString(); + BaseApiResponse> response = new BaseApiResponse<>(); + + String playerId = params.get("playerId") == null ? null : params.get("playerId").toString(); + List rangeDate = params.get("rangeDate") == null ? null : (ArrayList) params.get("rangeDate"); + + String groupName = JWT.decode(token).getClaim("group_name").asString(); + boolean viewApproval = sysGroupPermissionService.checkGroupPermission(groupName, "10001_05"); + //TODO + viewApproval = true; + if (!viewApproval){ + response.setSuccess(Boolean.FALSE); + response.setLogMessage("No Permission"); + response.setMessage("No Permission"); + return response; + } + + List bookingList = new ArrayList<>(); + List approvalList = approvalRoutingDao.getApprovalList(userId); + List bookingIds = approvalList.stream().map(CfgApprovalRouting::getBookingId).toList(); + String bookingIdsParam = bookingIds.stream().map(String::valueOf).collect(Collectors.joining(";")); + ApprovalGamingDataResult approvalData = bookingIds.isEmpty() + ? new ApprovalGamingDataResult() + : this.getApprovalData(bookingIdsParam).getData(); + List waitListData = approvalData.getRecords(); + boolean hasPlayerId = playerId != null && !playerId.trim().isEmpty(); + String trimmedPlayerId = hasPlayerId ? playerId.trim() : null; + // 到期判定:仅当当前日期已超过 checkinDate(nowDate > checkinDate)才设为 AE + Date now = new Date(); + SimpleDateFormat dateOnlyFormat = new SimpleDateFormat("yyyy-MM-dd"); + + // 处理日期范围:rangeDate 可能为 null / 空 / 1 个 / 多个(且连续) + Date startDate = null; + Date endDate = null; + if (rangeDate != null && !rangeDate.isEmpty()) { + try { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + // 假设传入的日期字符串已按从小到大排好,如无保证也可以先 Collections.sort(rangeDate) + Collections.sort(rangeDate); + startDate = sdf.parse(rangeDate.get(0)); + endDate = sdf.parse(rangeDate.get(rangeDate.size() - 1)); + } catch (Exception e) { + LogUtil.error(ApprovalService.class, + "[getPendingApprovalList] parse rangeDate error: " + e.getMessage()); + } + } + + for (CfgApprovalRouting cfgApprovalRouting : approvalList) { + BookingsView booking = hasPlayerId + ? bookingViewDao.findByIdAndPlayerIdContainingIgnoreCase(cfgApprovalRouting.getBookingId(), trimmedPlayerId) + : bookingViewDao.findByid(cfgApprovalRouting.getBookingId()); + + if (booking == null) { + continue; + } + + // 如果已经到期:把路由与 booking 状态都更新为 AE,并从返回列表中剔除 + if (booking.getCheckinDate() != null) { + LocalDate nowDate = LocalDate.parse(dateOnlyFormat.format(now)); + LocalDate checkinDateOnly = LocalDate.parse(dateOnlyFormat.format(booking.getCheckinDate())); + long diffDays = ChronoUnit.DAYS.between(checkinDateOnly, nowDate); // now - checkin + + // 新规则: + // diffDays <= 0:未超过 checkinDate(含当天),不剔除 + // diffDays > 0:日期已超过 checkinDate,直接剔除(AE) + boolean shouldExpire = diffDays > 0; + + dateOnlyFormat.setTimeZone(TimeZone.getTimeZone("GMT+8")); + CfgSettings cutoffStartTime = settingService.getSettingByKey("VIEW_YESTERDAY_TODOLIST_START"); + CfgSettings cutoffEndTime = settingService.getSettingByKey("VIEW_YESTERDAY_TODOLIST_END"); + String cutoffStartTimeValue = cutoffStartTime != null ? cutoffStartTime.getKeyValues() : null; + String cutoffEndTimeValue = cutoffEndTime != null ? cutoffEndTime.getKeyValues() : null; + + if (shouldExpire && !isCurrentTimeWithinCutoffWindowGmt8(cutoffStartTimeValue, cutoffEndTimeValue)) { + cfgApprovalRouting.setBookingStatus("AE"); + cfgApprovalRouting.setUpdatedAt(now); + cfgApprovalRouting.setUpdatedBy(userId); + approvalRoutingDao.save(cfgApprovalRouting); + + Bookings entity = bookingDao.getById(cfgApprovalRouting.getBookingId()); + if (entity != null) { + entity.setApproveStatus("AE"); + entity.setUpdatedAt(now); + entity.setUpdatedBy(userId); + bookingDao.save(entity); + } + continue; + } + } + if (waitListData != null) { + // 根据bookingId匹配对应的ApprovalGamingData + for (ApprovalGamingData gamingData : waitListData) { + if (gamingData.getBookingId() != null && booking.getId() != null && gamingData.getBookingId().equals(booking.getId().toString())) { + booking.setR6Tpd(gamingData.getR6TPD()); + break; + } + } + } + if (startDate != null && endDate != null && booking.getCheckinDate() != null) { + Date checkin = booking.getCheckinDate(); + if (checkin.before(startDate) || checkin.after(endDate)) { + continue; + } + } + bookingList.add(booking); + } + + // 对bookingList进行排序: + // 1) 按 BookingView.checkinDate 日期部分升序(忽略时间) + // 2) 如果同一天,再按 R6TPD 降序 + Collections.sort(bookingList, (b1, b2) -> { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + + Date firstCheckInDate = b1.getCheckinDate(); + Date secondCheckInDate = b2.getCheckinDate(); + + if (firstCheckInDate == null && secondCheckInDate == null) { + // 同时为空,按 R6TPD 排 + } else if (firstCheckInDate == null) { + return 1; // d1 放后面 + } else if (secondCheckInDate == null) { + return -1; // d2 放后面 + } else { + int dateCompare = dateFormat.format(firstCheckInDate).compareTo(dateFormat.format(secondCheckInDate)); + if (dateCompare != 0) { + return dateCompare; + } + } + + // 同一天比较 R6TPD值 + double firstR6Tpd = 0.0; + double secondR6Tpd = 0.0; + try { + if (b1.getR6Tpd() != null && !b1.getR6Tpd().isEmpty()) { + String r6TpdStr1 = b1.getR6Tpd().replace(",", ""); + firstR6Tpd = Double.parseDouble(r6TpdStr1); + } + if (b2.getR6Tpd() != null && !b2.getR6Tpd().isEmpty()) { + String r6TpdStr2 = b2.getR6Tpd().replace(",", ""); + secondR6Tpd = Double.parseDouble(r6TpdStr2); + } + } catch (NumberFormatException e) { + // 解析错误视为0 + } + + // 按R6TPD降序排序 + return Double.compare(secondR6Tpd, firstR6Tpd); + }); + + response.setSuccess(true); + response.setData(bookingList); + return response; + } + + public BaseApiResponse getCountPendingApproval(HttpServletRequest request) { + String token = request.getHeader("Authorization"); + String userId = JWT.decode(token).getClaim("login_id").asString(); + BaseApiResponse response = new BaseApiResponse<>(); + response.setSuccess(true); + response.setData(approvalRoutingDao.countApprovalList(userId)); + return response; + } + + public BaseApiResponse rejectApprovalBooking(Long bookingId,String userId) throws StaleObjectStateException { + BaseApiResponse response = new BaseApiResponse<>(); + List bookingList = new ArrayList<>(); + CfgApprovalRouting approvalRouting = approvalRoutingDao.getByBookingId(bookingId); + Date now = new Date(); + System.out.println("Version"+approvalRouting.getVersion()); + if (approvalRouting != null && isCurrentUserInApproverList(approvalRouting.getApproverId(), userId) + && "AP".equals(approvalRouting.getBookingStatus())) { + LogUtil.info(ApprovalService.class,"Reject Approval.UserId:"+userId); + approvalRouting.setBookingStatus("AR"); + CfgApprovalRouting changeRecord = approvalRoutingDao.save(approvalRouting); + + if (changeRecord==null) { + response.setSuccess(false); + response.setLogMessage("SUBMIT_APPROVAL_FAIL"); + response.setMessage("Submit approval fail,Record status has been changed"); + return response; + } + + Bookings booking = bookingDao.getById(approvalRouting.getBookingId()); + booking.setApprovedId(Long.valueOf(userId)); + booking.setApprovedAt(now); + booking.setApproveStatus("AR"); + bookingDao.save(booking); + response.setSuccess(true); + response.setData(approvalMapper.toRejectApprovalResponse(booking)); + }else{ + response.setSuccess(false); + response.setLogMessage("REJECT BOOKING FALSE"); + response.setMessage("Reject booking fail,please refresh record and retry"); + } + return response; + } + + public BaseApiResponse getApprovalDetail(HttpServletRequest request, Map params) throws Exception { + + String token = request.getHeader("Authorization"); + String playerId = params.get("playerId") == null ? null : params.get("playerId").toString(); + String userId = JWT.decode(token).getClaim("login_id").asString(); + BaseApiResponse response = new BaseApiResponse<>(); +// 获取对应 playerId 且 approvalStatus 为 AP 的 booking 记录 + List bookingList = bookingViewDao.getPendingApprovalBookingList(playerId,userId); + ObjectMapper mapper = new ObjectMapper(); + + List idList = new ArrayList<>(); +// 循环配置每个Record的Player + for (BookingsView booking : bookingList) { + // 收集booking.getId() + idList.add(String.valueOf(booking.getId())); + String sharer = booking.getSharer(); + JsonNode jsonArray = mapper.readTree(sharer); + + List playerInfoList = new ArrayList<>(); + for (JsonNode person : jsonArray) { + String sharerId = person.get("sharerId")!=null?person.get("sharerId").asText():""; + String name = person.get("name")!=null?person.get("name").asText():""; + playerInfoList.add(sharerId + " " + name); + } + String joinedResult = String.join(";", playerInfoList); + booking.setSharer(joinedResult); + } + // 用分号拼接所有ID +// Call Eab api 获取 player 的 GamingData + ApprovalGamingDataResult approvalData = this.getApprovalData(String.join(";", idList)).getData(); + List approvalRoutingList = new ArrayList<>(); + for (BookingsView booking : bookingList) { + approvalRoutingList.add(approvalRoutingDao.getByBookingId(booking.getId())); + } + + ApprovalDetail approvalDetail = new ApprovalDetail(); + approvalDetail.setCfgApprovalRoutingList(approvalRoutingList); + approvalDetail.setApprovalGamingData(approvalData.getRecords()); + approvalDetail.setBookingsViewList(bookingList); + if (!approvalDetail.getBookingsViewList().isEmpty()) { + response.setSuccess(true); + response.setData(approvalDetail); + }else { + response.setSuccess(false); + response.setLogMessage("GET_APPROVAL_DETAIL_FALSE"); + } + return response; + } + + public BaseApiResponse submitApproval(String bookingId,String checkinDate,String checkoutDate,String userId,HttpServletRequest request) throws Exception { + BaseApiResponse response = new BaseApiResponse<>(); + SysLogBooking sysLogBooking = new SysLogBooking(); + ArrayList addList = new ArrayList(); + Gson gson = new Gson(); + CfgApprovalRouting approvalRouting = approvalRoutingDao.getByBookingId(Long.valueOf(bookingId)); + LogUtil.info(ApprovalService.class,"Submitting Approval.UserId:"+userId+"BookingId"+bookingId + +"CheckinDate"+checkinDate+"CheckoutDate"+checkoutDate); + Date now = new Date(); + + //判断approverId 和 当前userId是否相同 + if (approvalRouting != null && isCurrentUserInApproverList(approvalRouting.getApproverId(), userId) + && "AP".equals(approvalRouting.getBookingStatus())) { + LogUtil.info(ApprovalService.class,"Submit Approval.UserId:"+userId); + System.out.println("Version = "+approvalRouting.getVersion()); + //相同 处理approvalRouting记录 并调用 Call OWS createbooking + approvalRouting.setBookingStatus("AA"); + CfgApprovalRouting changeRecord = approvalRoutingDao.save(approvalRouting); + + //处理Pending Approval Booking 记录 + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + Date checkin = dateFormat.parse(checkinDate); + Date checkout = dateFormat.parse(checkoutDate); + String userName = null; + CfgSettings emailAddress = settingService.getSettingByKey(SysConstants.MGM_EMAIL_ADDRESS); + + if(request!=null) { + LoginUserInfo userInfo = SysCommon.parseUserFromToken(String.valueOf(request)); + if (userInfo != null) { + userId = userInfo.getLoginId(); + if(!StringUtils.isEmpty(userId)) { + userId = Strings.CS.replace(userId, "@mgm.mo", ""); + } + userName = userInfo.getDisplayName(); + if(userId!=null) { + try { + Long checkUserId=Long.valueOf(userId); + BaseApiResponse userInfoByUserId = mgmUserService.findUserInfoByUserId(userId); + UserInfoApiRecord newUserInfo = userInfoByUserId.getData(); + userName = newUserInfo.getUserName(); + } catch (Exception e) { + userName = userId; + userId = null; + } + } + } + } + + Date creatdDate = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + Bookings originBooking = bookingDao.getById(approvalRouting.getBookingId()); + originBooking.setApproveStatus("AA"); + originBooking.setApprovedAt(now); + originBooking.setApprovedBy(userName); + if (userId != null) { + originBooking.setApprovedId(Long.valueOf(userId)); + } + if (!Strings.CS.equals(originBooking.getCheckinDate().toString(),checkinDate)){ + SysLogBooking newLogBooking = gson.fromJson(gson.toJson(sysLogBooking), SysLogBooking.class); + newLogBooking.setOccurTime(now); + newLogBooking.setBookId(Long.valueOf(bookingId)); + newLogBooking.setEventCode("Check In Date"); + newLogBooking.setChangeFrom(DateTimeUtil.getDateByFormat(originBooking.getCheckinDate(), "yyyy-MM-dd")); + newLogBooking.setChangeTo(checkinDate); + newLogBooking.setLoginId(userId); + newLogBooking.setLoginName(userId); + addList.add(newLogBooking); + + originBooking.setCheckinDate(checkin); + } + if(!Strings.CS.equals(originBooking.getCheckoutDate().toString(),checkoutDate)){ + SysLogBooking newLogBooking = gson.fromJson(gson.toJson(sysLogBooking), SysLogBooking.class); + newLogBooking.setOccurTime(now); + newLogBooking.setBookId(Long.valueOf(bookingId)); + newLogBooking.setEventCode("Check Out Date"); + newLogBooking.setChangeFrom(DateTimeUtil.getDateByFormat(originBooking.getCheckoutDate(), "yyyy-MM-dd")); + newLogBooking.setChangeTo(checkoutDate); + newLogBooking.setLoginId(userId); + newLogBooking.setLoginName(userId); + addList.add(newLogBooking); + + originBooking.setCheckoutDate(checkout); + } + BookingsView bookingView = bookingViewDao.findById(Long.parseLong(bookingId)); + // 获取Property + CfgProperties properties = propertyDao.getById(originBooking.getPropertyId()); + + + Boolean isOverBook = this.checkIsOverbook(bookingView.getRoomId(), bookingView.getCheckinDate(), + bookingView.getCheckoutDate(), bookingView.getPropertyId(), bookingView.getBlockId()); + Boolean isOtherOverBook = this.checkOtherIsOverbook(Math.toIntExact(originBooking.getRoomId()), originBooking.getCheckoutDate(), + originBooking.getCheckinDate(), originBooking.getPropertyId(), originBooking.getSegmentId()); + + + if (Strings.CS.equals(originBooking.getBookType(),"0")){ + //create 的情况 + LogUtil.info(ApprovalService.class,"Submitting Approval.BookingID:"+bookingId+"|bookingType:Create"); + bookingDao.save(originBooking); + BookingsView originBookingView = bookingViewDao.findById(Long.parseLong(bookingId)); + originBookingView = this.getEmailInfo(originBookingView,originBookingView.getCreatedBy()).getData(); + +// 判断是OPETA或OTHER Property + if(Strings.CS.equals(properties.getCategory(),"OPERA")) { +// OPERA 先创建 newBooking 再 call OWS,避免 callOWSCreateBooking 内部把同一笔记录的 status 改成 N 覆盖掉 origin 的 AA + Bookings newBooking = new Bookings(); + BeanUtils.copyProperties(originBookingView, newBooking, "id"); + // BookingsView 中 roomId/blockId 为 Long,Bookings 为 Integer,copyProperties 会跳过;View 无 bookingTypeId + + newBooking.setApprovalBookingId(String.valueOf(originBooking.getId())); + + if (originBookingView.getRoomId() != null) { + newBooking.setRoomId(originBookingView.getRoomId()); + } else if (originBooking.getRoomId() != null) { + newBooking.setRoomId(originBooking.getRoomId()); + } + if (originBookingView.getBlockId() != null) { + newBooking.setBlockId(originBookingView.getBlockId()); + } else if (originBooking.getBlockId() != null) { + newBooking.setBlockId(originBooking.getBlockId()); + } + if (originBooking.getBookingTypeId() != null) { + newBooking.setBookingTypeId(originBooking.getBookingTypeId()); + } + newBooking.setApproveStatus("PN"); +// newBooking.setLastOperaStatus("RESERVED"); + newBooking.setApprovedBy(userName); + if (userId != null) { + newBooking.setApprovedId(Long.valueOf(userId)); + } + newBooking.setApprovalReason(approvalRouting.getApprovalReason()); + bookingDao.save(newBooking); + + if (ctrlMsgSender != null) { + if (SysCommon.jmsRunning) { + ctrlMsgSender.sendMessage("CREATE_OPERA_BOOKING", newBooking); + } else { + bookingService.callOWSCreateBooking(newBooking); + } + } + } else if (Strings.CS.equals(properties.getCategory(),"DAYLIGHT")) { + Bookings newBooking = new Bookings(); + BeanUtils.copyProperties(originBookingView, newBooking, "id"); + // BookingsView 中 roomId/blockId 为 Long,Bookings 为 Integer,copyProperties 会跳过;View 无 bookingTypeId + + newBooking.setApprovalBookingId(String.valueOf(originBooking.getId())); + newBooking.setDateList(originBooking.getDateList()); + newBooking.setMember(originBooking.getMember()); + + if (originBookingView.getRoomId() != null) { + newBooking.setRoomId(originBookingView.getRoomId()); + } else if (originBooking.getRoomId() != null) { + newBooking.setRoomId(originBooking.getRoomId()); + } + if (originBookingView.getBlockId() != null) { + newBooking.setBlockId(originBookingView.getBlockId()); + } else if (originBooking.getBlockId() != null) { + newBooking.setBlockId(originBooking.getBlockId()); + } + if (originBooking.getBookingTypeId() != null) { + newBooking.setBookingTypeId(originBooking.getBookingTypeId()); + } + newBooking.setApproveStatus("PN"); +// newBooking.setLastOperaStatus("RESERVED"); + newBooking.setApprovedBy(userName); + if (userId != null) { + newBooking.setApprovedId(Long.valueOf(userId)); + } + newBooking.setApprovalReason(approvalRouting.getApprovalReason()); + bookingDao.save(newBooking); + + if (ctrlMsgSender != null) { + if (SysCommon.jmsRunning) { + ctrlMsgSender.sendMessage("CREATE_DAYLIGHT_BOOKING", newBooking); + } else { + bookingService.callDaylightUpsertReservation(newBooking, "CREATE_BOOKING"); + } + } + }else { + //判断是否OverBooking + if((isOverBook&&originBooking.getBlockId()!=null)||(isOtherOverBook&&originBooking.getSegmentId()!=null)) { + Bookings emailBook = originBooking; + Email email = new Email(); + + email.setBookId(originBooking.getId()); + email.setCreatedAt(creatdDate); + email.setCreatedBy(originBooking.getCreatedBy()); + email = SendEmail.sendApprovalNewEmail(emailBook, originBookingView,email,userId,userName,true,false,emailAddress.getKeyValues()); + if(email.getStatus()==1) { + originBooking.setApproveStatus("AA"); + bookingDao.save(originBooking); + } + emailDao.save(email); + }else{ + //Other Property 去本地createBooking + Bookings newBooking = new Bookings(); + BeanUtils.copyProperties(originBooking, newBooking,"id"); + newBooking.setApproveStatus("PN"); + newBooking.setCheckinDate(checkin); + newBooking.setCheckoutDate(checkout); + newBooking.setLastOperaStatus("PENDING"); + newBooking.setApprovedBy(userName); + newBooking.setApprovedId(Long.valueOf(userId)); + //获取other room status + CfgOtherRoomStatus roomStatus = roomStatusDao.findByStatusName("Pending"); + if(roomStatus!=null) { + newBooking.setOtherRoomStatusId(roomStatus.getId()); + } + bookingDao.save(newBooking); + //扣减房间 + nonMGMBookingService.processOtherAllotment(newBooking.getRoomId(), newBooking.getCheckoutDate(), + newBooking.getCheckinDate(), newBooking.getPropertyId(), newBooking.getSegmentId()); + } + } +// 判断是否为 R2 或者 Y2房型 是的话 发Email + if((StringUtils.equals(originBooking.getRoomTypeCode(), "R2"))|| + StringUtils.equals(originBooking.getRoomTypeCode(), "Y2")) { + Bookings emailBook = originBooking; + Email email = new Email(); + + email.setBookId(originBooking.getId()); + email.setCreatedAt(creatdDate); + email.setCreatedBy(originBooking.getCreatedBy()); + + email = SendEmail.sendApprovalNewEmail(emailBook, originBookingView,email,userId,userName,false,true,emailAddress.getKeyValues()); + emailDao.save(email); + } + + response.setSuccess(true); + response.setData(approvalMapper.toSubmitApprovalResponse(originBooking)); + }else{ + LogUtil.info(ApprovalService.class,"Submitting Approval.BookingID:"+bookingId+"|bookingType:Extend"); + //获取Property + if(Strings.CS.equals(properties.getCategory(),"OPERA")){ + //Send mgm booking email + BookingsView originBookingView = bookingViewDao.findById(Long.parseLong(originBooking.getApprovalBookingId())); + originBookingView = this.getEmailInfo(originBookingView,originBookingView.getCreatedBy()).getData(); + Bookings emailBook = originBooking; + Email email = new Email(); + + email.setBookId(originBooking.getId()); + email.setCreatedAt(creatdDate); + email.setCreatedBy(originBooking.getCreatedBy()); + + email = SendEmail.sendApprovalExtendEmail(emailBook, originBookingView,email,userId,userName,originBookingView,false,emailAddress.getKeyValues()); + LogUtil.info(ApprovalService.class,"Send Email Approved Id = "+originBooking.getId()); + if(email.getStatus()==1) { + originBooking.setApproveStatus("AA"); + bookingDao.save(originBooking); + emailDao.save(email); + + response.setSuccess(true); + response.setData(approvalMapper.toSubmitApprovalResponse(originBooking)); + }else{ + response.setSuccess(false); + response.setLogMessage("Send Email Failed"); + response.setMessage("Send Email Failed"); + } + }else{ + //send email instead of sync other booking + BookingsView originBookingView = bookingViewDao.findById(Long.parseLong(originBooking.getApprovalBookingId())); + originBookingView = this.getEmailInfo(originBookingView,originBookingView.getCreatedBy()).getData(); + Email email = new Email(); + + email.setBookId(originBooking.getId()); + email.setCreatedAt(creatdDate); + email.setCreatedBy(originBooking.getCreatedBy()); + + email = SendEmail.sendApprovalExtendEmail(originBooking, originBookingView,email,userId,userName,bookingView,isOtherOverBook,emailAddress.getKeyValues()); + if(email.getStatus()==1) { + originBooking.setApproveStatus("AA"); + bookingDao.save(originBooking); + emailDao.save(email); + + response.setSuccess(true); + response.setData(approvalMapper.toSubmitApprovalResponse(originBooking)); + }else{ + response.setSuccess(false); + response.setMessage("Send Email Failed"); + response.setLogMessage("Send Email Failed"); + } + } + } + if(addList.size()>0) sysLogBookingDao.saveAll(addList); + }else { + response.setSuccess(false); + response.setMessage("Submit Approval Failed,BookingId:"+bookingId); + response.setLogMessage("Approve record fail,please refresh record and retry"); + } + return response; + } + + public BaseApiResponse>> batchApproval(HttpServletRequest request,Map params) throws Exception { + String token = request.getHeader("Authorization"); + String userId = JWT.decode(token).getClaim("login_id").asString(); + List> submitInfoList = this.convertToList(params.get("submitInfoList")); + BaseApiResponse>> response = new BaseApiResponse<>(); + List failApprovalList = new ArrayList<>(); + LogUtil.info(ApprovalService.class,"Batch Approval.UserId:"+userId+" submitInfoList:"+submitInfoList); +// 循环拿到每个提交的信息 + for (Map submitInfo : submitInfoList) { + String bookingId = String.valueOf(submitInfo.get("bookingId")); + String checkinDate = submitInfo.get("checkinDate"); + String checkoutDate = submitInfo.get("checkoutDate"); + if (bookingId != null && checkinDate != null && checkoutDate != null) { +// 调用submitApproval方法 + BaseApiResponse funcResponse = this.submitApproval(bookingId, checkinDate, checkoutDate, userId, request); +// 如果submitApproval失败了 放入failApprovalList中 + if (!funcResponse.isSuccess()) failApprovalList.add(bookingId); + }else{ + failApprovalList.add(bookingId); + } + } +// 根据failApprovalList 判断是否成功 + if (failApprovalList.isEmpty()) { + response.setSuccess(true); + response.setData(submitInfoList); + }else{ + response.setSuccess(false); + response.setLogMessage("Failed to Approval Booking,BookingIds:"+failApprovalList.toString()); + LogUtil.error(ApprovalService.class,"Batch Approval Fail,FailApprovalList:"+failApprovalList); + } + return response; + } + +// public ServiceResult changeMisCharge(Long bookingId,String misCharge,String userId) throws Exception { +// ServiceResult processResult = new ServiceResult(); +// List failApprovalList = new ArrayList<>(); +//// 获取到对应的booking +// Bookings bookings = bookingDao.getById(bookingId); +// Boolean isMock = sysSettingService.isMockReplicate(); +// +// // 与 createBooking 中 operaComment 日期段一致(英文 Mar 30,非 Date#toString()) +// String dateRange = DateTimeUtil.formatOperaCommentStayDateRange( +// bookings.getCheckinDate(), bookings.getCheckoutDate(), bookings.getNumOfNight()); +// +// +// String newOperaComment = null; +// // 获取Booking的Comment +// +// Integer bookingCommentId = bookings.getOperaCommentId()!=null?Integer.valueOf(bookings.getOperaCommentId()):null; +// Integer resvNameId = bookings.getResvId()!=null?Integer.valueOf(bookings.getResvId()):null; +// +// LogUtil.info(ApprovalService.class,"Start GetOperaComment CommentId:"+bookingCommentId+" resvNameId:"+resvNameId); +// +// List bookingCommentByCommentId = operaDBBookingService.getBookingCommentByCommentId(bookingCommentId,resvNameId); +// +// LogUtil.info(ApprovalService.class,"End GetOperaComment"); +// +// String commentType = null; +// +// if (bookingCommentByCommentId != null && !bookingCommentByCommentId.isEmpty()) { +// +// //TODO 先用get 在升级到JDK21后 使用getLast替换掉 +// OperaComment operaComment = bookingCommentByCommentId.getLast(); +// bookings.setOperaComment(operaComment.getComments()); +// bookings.setOperaCommentId(operaComment.getResvCommentId()); +// commentType = operaComment.getCommentType(); +// LogUtil.info(ApprovalService.class,"Get Comment Success:"+operaComment.getComments()+"CommentId:"+operaComment.getResvCommentId()); +// +// }else{ +// +// LogUtil.info(ApprovalService.class,"Get Comment Failed,bookingCommentByCommentId is Empty"); +// +// } +// +// String operaComment = bookings != null ? bookings.getOperaComment() : null; +// newOperaComment = operaComment == null ? "" : operaComment; +//// 判断CreateBooking时是否有传入MisCharge +//// 没有 -> operaComment 是固定模板((RM)COMP ..APP\n\nSTAY DATE,OD,BOOKER) +//// 有 -> operaComment 里已经包含 mischarge 对应的 INC 行((RM+INC$*** )... / INC.CHRG$***...) +// +//// 修改misCharge + 修改 operaComment +// String misChargeValue = misCharge == null ? "" : misCharge.trim(); +// +// // 保存旧 misCharge,用于区分“情况 1 / 情况 2” +// String oldMisCharge = bookings.getMiscCharge(); +// boolean hadOldMisCharge = oldMisCharge != null && !oldMisCharge.trim().isEmpty(); +// +// // 统一换行符,避免 \r\n 或 ' ' 导致 indexOf/replace 命中失败 +// if (newOperaComment != null) { +// newOperaComment = newOperaComment.replace("\r\n", "\n").replace("\r", "\n"); +// // DB/OPERA 里可能已是 ' ',先还原成 '\n' 供下方逻辑判断 +// newOperaComment = newOperaComment.replace(" ", "\n"); +// newOperaComment = newOperaComment.replace("$", "$"); +// } +// +// bookings.setMiscCharge(misChargeValue); +// +// if (!misChargeValue.isEmpty() && !newOperaComment.isEmpty()) { +// // 若 misCharge 以前为空,且当前 comment 仍是 createBooking 的默认模板,则视为情况 1 +// boolean isBaseTemplate = +// newOperaComment.contains("(RM)COMP ..APP") +// && newOperaComment.contains("\n\n"+dateRange+","+bookings.getSourceCode()+","+userId) +// && !newOperaComment.contains("INC.CHRG$"); +// +// String amendLine = "AMEND INC.CHRG $" + misChargeValue + " AS "+userId+" ..APP"; +// +// if (!hadOldMisCharge && isBaseTemplate) { +// newOperaComment = newOperaComment +// .replace("(RM)COMP ..APP", "(RM+INC$" + misChargeValue + ")COMP ..APP"); +// +// // 在 \n\n 后、STAY DATE 行前插入 +// String target = "\n\n"+dateRange+","+bookings.getSourceCode()+","+userId; +// if (newOperaComment.contains(target)) { +// newOperaComment = newOperaComment.replace( +// target, +// "\n\n" + amendLine + "\n" + target.substring(2) +// ); +// } else { +// int nnIdx = newOperaComment.indexOf("\n\n"); +// if (nnIdx >= 0) { +// newOperaComment = newOperaComment.substring(0, nnIdx + 2) + amendLine + "\n" + newOperaComment.substring(nnIdx + 2); +// } else { +// newOperaComment = newOperaComment + "\n" + amendLine; +// } +// } +// } else { +// // 情况 2:operaComment 已经包含 INC.CHRG$***,需要把 misCharge 替换为新值,并在第二个换行符后的下一行插入 amendLine +// +// // 替换 RM 里的 INC$ 值 +// int rmIdxFull = newOperaComment.indexOf("(RM+INC$"); +// if (rmIdxFull >= 0) { +// int valStart = rmIdxFull + "(RM+INC$".length(); +// int valEnd = newOperaComment.indexOf(")COMP", valStart); +// if (valEnd > valStart) { +// newOperaComment = newOperaComment.substring(0, valStart) + misChargeValue + newOperaComment.substring(valEnd); +// } +// } +// int rmIdxHalf = newOperaComment.indexOf("(RM+INC$"); +// if (rmIdxHalf >= 0) { +// int valStart = rmIdxHalf + "(RM+INC$".length(); +// int valEnd = newOperaComment.indexOf(")COMP", valStart); +// if (valEnd > valStart) { +// newOperaComment = newOperaComment.substring(0, valStart) + misChargeValue + newOperaComment.substring(valEnd); +// } +// } +// +// // 不移除旧的 AMEND 行:每次修改都在旧 AMEND 行上方新增一行 +// // 在 \n\n 后插入一行(\n\n 下一行即为原本第一条 AMEND 行) +// String doubleNl = "\n\n"; +// int nnIdx = newOperaComment.indexOf(doubleNl); +// if (nnIdx >= 0) { +// newOperaComment = newOperaComment.substring(0, nnIdx + doubleNl.length()) +// + amendLine + "\n" +// + newOperaComment.substring(nnIdx + doubleNl.length()); +// } else { +// newOperaComment = newOperaComment + "\n" + amendLine; +// } +// } +// +// +// }else{ +// newOperaComment = "(RM+INC$" + misCharge + ")COMP ..APP\n\n" +// + "INC.CHRG$" + misCharge + "COMP BY "+bookings.getCreatedBy()+" ..APP\n" +// + dateRange+","+bookings.getSourceCode()+","+userId; +// } +// +// // 最终落库 / 发送到 OPERA 前,将内部换行符从 '\n' 转成 ' ' +// if (newOperaComment != null && !newOperaComment.isEmpty()) { +// newOperaComment = newOperaComment.replace("\n", " "); +// newOperaComment = newOperaComment.replace("$", "$"); +// } +// if (StringUtils.isNotBlank(userId)) { +// bookings.setUpdatedBy(userId); +// bookings.setUpdatedAt(new Date()); +// } +// Bookings changedBooking = null; +// if (isMock) { +// bookings.setOperaComment(newOperaComment); +// changedBooking = bookingDao.save(bookings); +// } else { +// +// if(bookings.getConfirmationNo()!=null){ +// //调用OWS方法去OPERA修改MisCharge +// ModifyBookingRequest misChargeRequest = new ModifyBookingRequest(); +// misChargeRequest.setMisCharge(misChargeValue); +// misChargeRequest.setBooking(bookings); +// operaService.modifyMisCharge(misChargeRequest); +// LogUtil.info(ApprovalService.class,"new Comment"+newOperaComment); +// +// //调用OWS方法去OPERA修改Comment +// CfgProperties property = propertyDao.getById(bookings.getPropertyId()); +// GuestRequestsRequest cashCommentRequest = new GuestRequestsRequest(); +// JSONObject cashCommentResponse = new JSONObject(); +// cashCommentRequest.setProperty(property); +// cashCommentRequest.setComment(newOperaComment); +// cashCommentRequest.setConfirmationNo(bookings.getConfirmationNo()); +// cashCommentRequest.setCommentId(bookings.getOperaCommentId()); +// LogUtil.info(ApprovalService.class,"CommentId"+bookings.getOperaCommentId()+"CommentType"+commentType); +//// 判断如果没有Cooment就ADD 如果有的话 就去UPDATE +// +// if (bookings.getOperaCommentId()!=null){ +// cashCommentRequest.setActionType("UPDATE"); +// cashCommentRequest.setCommentId(bookings.getOperaCommentId()); +// if (commentType!=null){ +// cashCommentRequest.setCommentType(commentType); +// } +// }else { +// cashCommentRequest.setActionType("ADD"); +// cashCommentRequest.setCommentType("CASHIER"); +// } +// LogUtil.info(ApprovalService.class,"Action Type:"+cashCommentRequest.getActionType()); +// LogUtil.info(ApprovalService.class,"start opera change comment"); +// cashCommentResponse = operaService.guestRequests(cashCommentRequest); +// LogUtil.info(ApprovalService.class,"end opera change comment"); +// +// if (cashCommentResponse!=null){ +// String commentId = cashCommentResponse.get("commentId").toString(); +// if (commentId != null && !commentId.isEmpty()) { +// bookings.setOperaCommentId(commentId); +// } +// }else{ +// +// } +// +// } +// +// bookings.setOperaComment(newOperaComment); +// changedBooking = bookingDao.save(bookings); +// +// } +// +// +// processResult.setSuccess(true); +// processResult.setReturnData(changedBooking); +// return processResult; +// } + + public BaseApiResponse> batchReject(List submitBookingIds,String userId) throws Exception { + BaseApiResponse> response = new BaseApiResponse<>(); + List failApprovalList = new ArrayList<>(); +// 循环拿到每个提交的信息 + for (String bookingId : submitBookingIds) { + if (bookingId != null) { +// 调用submitApproval方法 + BaseApiResponse rejectResponse = this.rejectApprovalBooking(Long.valueOf(bookingId), userId); +// 如果submitApproval失败了 放入failApprovalList中 + if (!rejectResponse.isSuccess()) failApprovalList.add(bookingId); + }else{ + failApprovalList.add(bookingId); + } + } +// 根据failApprovalList 判断是否成功 + if (failApprovalList.isEmpty()) { + response.setSuccess(true); + response.setData(submitBookingIds); + }else{ + response.setSuccess(false); + response.setMessage("Failed to Reject Booking,BookingIds:"+failApprovalList.toString()); + } + return response; + } + + /** + * approver_id 可能为单个工号,或以英文逗号/中文逗号/分号分隔的多个工号。 + * 分隔后逐项 trim 再与 userId 精确比较,避免用 contains 导致 "800002" 误匹配 "80002"。 + */ + private static boolean isCurrentUserInApproverList(String approverIdField, String userId) { + if (StringUtils.isBlank(approverIdField) || StringUtils.isBlank(userId)) { + return false; + } + String uid = userId.trim(); + for (String token : approverIdField.split("[,,;;]")) { + LogUtil.info(ApprovalService.class,"approverIdField:"+token); + LogUtil.info(ApprovalService.class,"Current Id:"+uid); + if (uid.equals(token.trim())) { + LogUtil.info(ApprovalService.class,"=-=---=-=-=-=-== TRUE"); + return true; + } + } + LogUtil.info(ApprovalService.class,"=-=---=-=-=-=-== FALSE"); + return false; + } + + @SuppressWarnings("unchecked") + public List> convertToList(Object obj) { + if (obj instanceof List list) { + if (list.isEmpty() || list.getFirst() instanceof Map) { + return (List>) list; + } + } + return new ArrayList<>(); + } + + private BaseApiResponse getEmailInfo(BookingsView bookView, String userId) { + BaseApiResponse response = new BaseApiResponse<>(); + if(bookView!=null) { + JSONArray dynList = !StringUtils.isEmpty(bookView.getSharer())&&!Strings.CS.equals("[]", bookView.getSharer())? + JSONArray.parseArray(bookView.getSharer()) :new JSONArray(); + StringBuilder sharerString = new StringBuilder(); + if (!dynList.isEmpty()) { + for (Object o : dynList) { + Gson gson = new Gson(); + JSONObject shareObj = (JSONObject) o; + String sharePlayerId = shareObj.getString("playerId"); + String shareName = shareObj.getString("name"); + LogUtil.info(BookingService.class, + "[editBooking] sharePlayerId " + gson.toJson(sharePlayerId)); + LogUtil.info(BookingService.class, + "[editBooking] shareName " + gson.toJson(shareName)); + if (!StringUtils.isEmpty(sharePlayerId)) { + sharerString.append(sharePlayerId).append(" ").append(shareName).append(" "); + } else if (!StringUtils.isEmpty(shareName)) { + sharerString.append(shareName).append(" "); + } else { + continue; + } + } + } + bookView.setSharerName(sharerString.toString()); + String playerId = bookView.getPlayerId()!=null? bookView.getPlayerId():null; + BaseApiResponse webPlayerProfileByPlayerId = playerService.findWebPlayerProfileByPlayerId(playerId); + if(webPlayerProfileByPlayerId.isSuccess()) { + try { + PlayerProfileEntry profile = webPlayerProfileByPlayerId.getData(); + bookView.setMemberTier(profile.getTierName()); + bookView.setMemberLastName(profile.getName()); + } catch (Exception e) { + LogUtil.error(ApprovalService.class,String.valueOf(e.getMessage())); + } + } + + } + response.setData(bookView); + return response; + } + //检查other booking是否overbook + public Boolean checkOtherIsOverbook(int roomId,Date checkoutDate,Date checkinDate,Long propertyId,Long segmentId) { + boolean isOverbook = false; + List roomIds = new ArrayList<>(); + roomIds.add(Long.valueOf(String.valueOf(roomId))); + Date endDate = DateTimeUtil.addDay(checkoutDate, -1); + List criterias = otherAllotmentDao.findByRoomIdInAndPropertyIdAndBookDateBetween + (roomIds,propertyId,checkinDate,endDate); + if(criterias.isEmpty()) isOverbook = true; + Long[] roomStatusId = otherRoomStatusDao.findIsPickUpId(); + for(CfgOtherAllotment c:criterias) { + CfgOtherAppChannel channel = new CfgOtherAppChannel(); + Set channels = c.getChannels(); + if(channels.isEmpty()) isOverbook = true; + for(CfgOtherAppChannel a:channels) { + if(a.getSegmentId()!=null&&segmentId!=null) { + if(a.getSegmentId().longValue()==segmentId.longValue()) { + channel = a; + int pickUp = 0; + Integer appChannel = 0; + pickUp = bookingDao.getOtherPickupBooking(propertyId, roomId, segmentId, c.getBookDate(), roomStatusId); + pickUp = pickUp+1; + if(channel.getAppChannel()!=null) { + appChannel = channel.getAppChannel(); + } + if(appChannel-pickUp<0) { + isOverbook = true; + break; + } + } + } + } + } + return isOverbook; + } + + //检查other booking是否overbook + public Boolean checkIsOverbook(Long roomId,Date checkinDate ,Date checkoutDate,Long propertyId,Long blockId) { + boolean isOverbook = false; + List roomIds = new ArrayList<>(); + roomIds.add(roomId); + Date endDate = DateTimeUtil.addDay(checkoutDate, -1); + List criterias = roomCriteriaDao.findByRoomIdInAndPropertyIdAndBookDateBetween + (roomIds,propertyId,checkinDate,endDate); + if(criterias.isEmpty()) isOverbook = true; + for(CfgRoomCriterias c:criterias) { + CfgAppChannel channel = new CfgAppChannel(); + Set channels = c.getChannels(); + if(channels.isEmpty()) isOverbook = true; + for(CfgAppChannel a:channels) { + if(a.getBlockId()!=null&&blockId!=null) { + if(a.getBlockId().longValue()==blockId.longValue()) { + channel = a; + int pickUp = 0; + int appChannel = 0; + pickUp = bookingDao.getPickupBooking(propertyId, roomId, blockId, c.getBookDate()); + pickUp = pickUp+1; + if(channel.getAppChannel()!=null) { + appChannel = channel.getAppChannel(); + } + if(appChannel-pickUp<0) { + isOverbook = true; + break; + } + } + } + + } + } + return isOverbook; + } + + public void setFailApprovalRouting(String bookingId){ + Bookings booking = bookingDao.findById(Long.valueOf(bookingId)).orElse(null); + Date now = new Date(); + booking.setApproveStatus("F"); + booking.setTryTime(5); + booking.setUpdatedAt(now); + bookingDao.save(booking); + } + +} diff --git a/src/main/java/com/mgm/mcrm/appsetting/controllers/CfgSettingController.java b/src/main/java/com/mgm/mcrm/appsetting/controllers/CfgSettingController.java new file mode 100644 index 0000000..9d92faf --- /dev/null +++ b/src/main/java/com/mgm/mcrm/appsetting/controllers/CfgSettingController.java @@ -0,0 +1,102 @@ +package com.mgm.mcrm.appsetting.controllers; + +import com.mgm.mcrm.appsetting.dtos.CfgSettingQueryRequest; +import com.mgm.mcrm.appsetting.dtos.SysSettingQueryRequest; +import com.mgm.mcrm.appsetting.models.CfgSettings; +import com.mgm.mcrm.appsetting.models.SysSetting; +import com.mgm.mcrm.appsetting.services.SysSettingService; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.common.utils.LogUtil; +import com.mgm.mcrm.common.utils.NetworkUtil; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import com.mgm.mcrm.appsetting.services.SettingService; + +import java.util.List; +import java.util.Map; + + +@RestController +@CrossOrigin(origins = "*") +@RequestMapping("/api") +public class CfgSettingController { + + @Resource + private SettingService settingService; + @Resource + private SysSettingService sysSettingService; + + @RequestMapping(value = "/web/setting/get_setting_by_key", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> getSettingByKey(HttpServletRequest request, @RequestBody CfgSettingQueryRequest params) throws Exception { + boolean isSuccess = false; + String processMessage=""; + String errorCode=""; + BaseApiResponse result = new BaseApiResponse<>(); + String keyName = params.getKeyName(); + CfgSettings setting = settingService.getSettingByKey(keyName); + isSuccess = setting != null; + if(isSuccess) { + processMessage = "Get Setting By Key Successed"; + result.setData(setting); + }else { + processMessage = "Get Setting By Key with Error"; + errorCode = "System Error"; + } + result.setSuccess(isSuccess); + result.setCode(errorCode); + result.setMessage(processMessage); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @RequestMapping(value = "/system/sys_setting/get", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> getSysSettingByKey(HttpServletRequest request, @RequestBody SysSettingQueryRequest queryFilter) { + BaseApiResponse result = new BaseApiResponse<>(); + //-- + String accessIp = NetworkUtil.getClientIpAddr(request); + LogUtil.info(CfgSettingController.class, "Client Connect with IP:"+ accessIp); + //-- + SysSetting sysSetting = sysSettingService.getSysSettingByKey(queryFilter.getKey()); + if(sysSetting!=null) { + result.setSuccess(true); + sysSetting.setInternalNetwork(NetworkUtil.isMatchInternal(accessIp)); + result.setData(sysSetting); + }else { + result.setSuccess(false); + result.setMessage("Query Failed with Error."); + result.setCode("ERR_DATA_NOT_FOUND"); + } + return ResponseEntity.status(HttpStatus.OK).body(result); + } + @RequestMapping(value = "/system/sys_setting/get_list", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity>> getSysSettings(HttpServletRequest request, @RequestBody(required=false) SysSettingQueryRequest queryFilter) { + boolean isSuccess = false; + String processMessage=""; + String errorCode=""; + BaseApiResponse result = new BaseApiResponse<>(); + //-- + String accessIp = NetworkUtil.getClientIpAddr(request); + LogUtil.info(CfgSettingController.class, "Client Connect with IP:"+ accessIp); + //-- + List sysSettings = sysSettingService.getSysSettingsAll(); + for(SysSetting sysSetting:sysSettings) { + sysSetting.setInternalNetwork(NetworkUtil.isMatchInternal(accessIp)); + } + if(sysSettings!=null) { + isSuccess = true; + processMessage = ""; + result.setData(sysSettings); + }else { + isSuccess = false; + processMessage = "Query Failed with Error."; + errorCode = "ERR_DATA_NOT_FOUND"; + } + //-- + result.setSuccess(isSuccess); + result.setCode(errorCode); + result.setMessage(processMessage); + return ResponseEntity.status(HttpStatus.OK).body(result); + } +} diff --git a/src/main/java/com/mgm/mcrm/appsetting/controllers/ConfigController.java b/src/main/java/com/mgm/mcrm/appsetting/controllers/ConfigController.java new file mode 100644 index 0000000..7be5f38 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/appsetting/controllers/ConfigController.java @@ -0,0 +1,158 @@ +package com.mgm.mcrm.appsetting.controllers; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import com.mgm.mcrm.appsetting.dtos.*; +import com.mgm.mcrm.appsetting.models.CfgSettings; +import com.mgm.mcrm.basesetting.property.models.CfgProperties; +import com.mgm.mcrm.basesetting.room.models.CfgRoomFeatures; +import com.mgm.mcrm.basesetting.room.models.CfgRoomTypes; +import com.mgm.mcrm.basesetting.room.models.CfgRooms; +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.booking.models.CfgBookingTypes; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import com.alibaba.fastjson.JSONObject; + +import com.mgm.mcrm.basesetting.room.repositories.BedTypeMappingDao.BedType; +import com.mgm.mcrm.appsetting.services.ConfigService; +import com.mgm.mcrm.common.utils.LogUtil; + +@RestController +@CrossOrigin(origins = "*") +@RequestMapping("/api") +public class ConfigController { + + @Resource + private ConfigService configService; + + @RequestMapping(value = "/app/config/property_list", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity>> queryCfgPropertys(HttpServletRequest request, @RequestBody(required=true) PropertyQueryRequest queryFilter) { + BaseApiResponse> processResult = new BaseApiResponse<>(); + //-- + List listCfgPropertys = configService.listProperty(queryFilter); + //-- + processResult.setSuccess(true); + processResult.setData(listCfgPropertys); + return ResponseEntity.status(HttpStatus.OK).body(processResult); + } + + @RequestMapping(value = "/app/config/room_list", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity>> queryRoom(HttpServletRequest request, @RequestBody(required=true) RoomQueryRequest queryFilter) { + BaseApiResponse> processResult = new BaseApiResponse<>(); + List listCfgRooms = configService.listRoom(queryFilter); + //-- + processResult.setSuccess(true); + processResult.setData(listCfgRooms); + return ResponseEntity.status(HttpStatus.OK).body(processResult); + } + + @RequestMapping(value = "/app/config/room_type_list", produces = "application/json;charset=UTF-8") + public ResponseEntity>> queryRoomType(HttpServletRequest request,@RequestBody(required=true) RoomTypeQueryRequest queryFilter) { + BaseApiResponse> processResult = new BaseApiResponse<>(); + //-- + List listCfgRoomTypes = configService.listRoomType(queryFilter); + processResult.setSuccess(true); + processResult.setData(listCfgRoomTypes); + return ResponseEntity.status(HttpStatus.OK).body(processResult); + } + + @RequestMapping(value = "/app/config/bed_type_list", produces = "application/json;charset=UTF-8") + public ResponseEntity>> queryBedType(HttpServletRequest request,@RequestBody(required=true) BedTypeQueryRequest queryFilter) { + BaseApiResponse> processResult = new BaseApiResponse<>(); + //-- + List listCfgBedTypes = configService.listBedType(queryFilter); + processResult.setData(listCfgBedTypes); + processResult.setSuccess(true); + return ResponseEntity.status(HttpStatus.OK).body(processResult); + } + + @RequestMapping(value = "/app/config/special_list", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity>> queryCfgRoomFeatures(HttpServletRequest request, @RequestBody(required=true) RoomFeatureQueryRequest queryFilter) { + BaseApiResponse> processResult = new BaseApiResponse<>(); + //-- + List listCfgRoomFeatures = configService.listRoomFeature(queryFilter); + processResult.setData(listCfgRoomFeatures); + processResult.setSuccess(true); + return ResponseEntity.status(HttpStatus.OK).body(processResult); + } + + @RequestMapping(value = "/app/config/criteria_list", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity>> queryRoomCriteria(HttpServletRequest request, @RequestBody(required=true) RoomCriteriaQueryRequest queryParas) throws Exception { + BaseApiResponse> processResult = new BaseApiResponse<>(); + //-- + Map listCfgCriterias = configService.listRoomCriteriaCalendar(queryParas); + processResult.setData(listCfgCriterias); + processResult.setSuccess(true); + return ResponseEntity.status(HttpStatus.OK).body(processResult); + } + + @RequestMapping(value = "/app/config/setting_list", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity>> queryRoomSetting(HttpServletRequest request) { + BaseApiResponse> processResult = new BaseApiResponse<>(); + //-- + LogUtil.info(ConfigController.class, + "[ConfigController] 开始获取设置列表"); + List listCfgRoomSetting = configService.listRoomSetting(); + processResult.setData(listCfgRoomSetting); + //-- + processResult.setSuccess(true); + + LogUtil.info(ConfigController.class, + "[ConfigController] 设置列表获取成功,准备返回结果"); + LogUtil.info(ConfigController.class, + "[ConfigController] === setting_list API执行完成 ==="); + return ResponseEntity.status(HttpStatus.OK).body(processResult); + } + + @RequestMapping(value = "/app/config/available_room_list", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity>> queryRoomCriteriaAvailableRoom(HttpServletRequest request, @RequestBody(required=true) AvailableRoomQueryRequest queryParas) { + BaseApiResponse> processResult = new BaseApiResponse<>(); + //-- + HashSet listCfgRooms = configService.listRoomCriteriaAvailableRoom(queryParas); + processResult.setData(listCfgRooms); + processResult.setSuccess(true); + processResult.setMessage("Query Success"); + return ResponseEntity.status(HttpStatus.OK).body(processResult); + } + + @RequestMapping(value = "/app/config/is_extend_booking", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity>> queryIsExtendBooking(HttpServletRequest request, @RequestBody(required=true) ExtendBookingQueryRequest queryParas) { + BaseApiResponse> processResult = new BaseApiResponse<>(); + //-- + List listBooking = configService.listIsExtendBooking(queryParas); + processResult.setData(listBooking); + processResult.setSuccess(true); + processResult.setMessage("Query Success"); + return ResponseEntity.status(HttpStatus.OK).body(processResult); + } + + @RequestMapping(value = "/app/config/booking_type_list", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity>> queryCfgBookingTypes(HttpServletRequest request) { + BaseApiResponse> processResult = new BaseApiResponse<>(); + List listCfgBookingTypes = configService.listAllBookingType(); + processResult.setData(listCfgBookingTypes); + processResult.setSuccess(true); + processResult.setMessage("Query Success"); + return ResponseEntity.status(HttpStatus.OK).body(processResult); + } + + @RequestMapping(value = "/app/config/get_waitlist_booking", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity>> queryGetWaitlistBooking(HttpServletRequest request, @RequestBody(required=true) WaitlistBookingQueryRequest queryParas) throws Exception { + BaseApiResponse> processResult = new BaseApiResponse<>(); + //-- + List listBooking = configService.getWaitlistBooking(queryParas); + processResult.setData(listBooking); + processResult.setSuccess(true); + processResult.setMessage("Query Success"); + return ResponseEntity.status(HttpStatus.OK).body(processResult); + } +} diff --git a/src/main/java/com/mgm/mcrm/appsetting/dtos/AvailableRoomQueryRequest.java b/src/main/java/com/mgm/mcrm/appsetting/dtos/AvailableRoomQueryRequest.java new file mode 100644 index 0000000..a9bbd3a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/appsetting/dtos/AvailableRoomQueryRequest.java @@ -0,0 +1,18 @@ +package com.mgm.mcrm.appsetting.dtos; + +import com.mgm.mcrm.common.dtos.BaseQueryRequest; +import com.mgm.mcrm.common.utils.DateTimeUtil; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Date; +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +public class AvailableRoomQueryRequest extends BaseQueryRequest { + private List selectDate; + private Long blockId; + private Long propertyId; + private Long roomId; +} diff --git a/src/main/java/com/mgm/mcrm/appsetting/dtos/BedTypeQueryRequest.java b/src/main/java/com/mgm/mcrm/appsetting/dtos/BedTypeQueryRequest.java new file mode 100644 index 0000000..35eeb95 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/appsetting/dtos/BedTypeQueryRequest.java @@ -0,0 +1,12 @@ +package com.mgm.mcrm.appsetting.dtos; + +import com.mgm.mcrm.common.dtos.BaseQueryRequest; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class BedTypeQueryRequest extends BaseQueryRequest { + private Long propertyId; + private Long roomId; +} diff --git a/src/main/java/com/mgm/mcrm/appsetting/dtos/CfgSettingQueryRequest.java b/src/main/java/com/mgm/mcrm/appsetting/dtos/CfgSettingQueryRequest.java new file mode 100644 index 0000000..57442b8 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/appsetting/dtos/CfgSettingQueryRequest.java @@ -0,0 +1,8 @@ +package com.mgm.mcrm.appsetting.dtos; + +import lombok.Data; + +@Data +public class CfgSettingQueryRequest { + private String keyName; +} diff --git a/src/main/java/com/mgm/mcrm/appsetting/dtos/ExtendBookingQueryRequest.java b/src/main/java/com/mgm/mcrm/appsetting/dtos/ExtendBookingQueryRequest.java new file mode 100644 index 0000000..baefc64 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/appsetting/dtos/ExtendBookingQueryRequest.java @@ -0,0 +1,20 @@ +package com.mgm.mcrm.appsetting.dtos; + +import com.mgm.mcrm.common.dtos.BaseQueryRequest; +import com.mgm.mcrm.common.utils.DateTimeUtil; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Date; +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +public class ExtendBookingQueryRequest extends BaseQueryRequest { + private String checkoutDate; + private String checkinDate; + private String playerId; + private String userId; + private String propertyId; + private String roomId; +} diff --git a/src/main/java/com/mgm/mcrm/appsetting/dtos/PropertyQueryRequest.java b/src/main/java/com/mgm/mcrm/appsetting/dtos/PropertyQueryRequest.java new file mode 100644 index 0000000..671ae3a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/appsetting/dtos/PropertyQueryRequest.java @@ -0,0 +1,14 @@ +package com.mgm.mcrm.appsetting.dtos; + +import com.mgm.mcrm.common.dtos.BaseQueryRequest; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class PropertyQueryRequest extends BaseQueryRequest { + private String searchCode; + private String searchName; + private String searchCategory; + private String searchId; +} diff --git a/src/main/java/com/mgm/mcrm/appsetting/dtos/RoomCriteriaQueryRequest.java b/src/main/java/com/mgm/mcrm/appsetting/dtos/RoomCriteriaQueryRequest.java new file mode 100644 index 0000000..7781691 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/appsetting/dtos/RoomCriteriaQueryRequest.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.appsetting.dtos; + +import com.mgm.mcrm.common.dtos.BaseQueryRequest; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class RoomCriteriaQueryRequest extends BaseQueryRequest { + private Long bookingTypeId; + private Long blockId; + private Long segmentId; + private Long propertyId; + private Long roomId; + private boolean coded; + private String userId; + private String userName; + private String playerId; + private Long sectionId; + private Long bedTypeId; +} diff --git a/src/main/java/com/mgm/mcrm/appsetting/dtos/RoomFeatureQueryRequest.java b/src/main/java/com/mgm/mcrm/appsetting/dtos/RoomFeatureQueryRequest.java new file mode 100644 index 0000000..ef44938 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/appsetting/dtos/RoomFeatureQueryRequest.java @@ -0,0 +1,17 @@ +package com.mgm.mcrm.appsetting.dtos; + +import com.mgm.mcrm.common.dtos.BaseQueryRequest; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class RoomFeatureQueryRequest extends BaseQueryRequest { + @NotBlank + private String category; + private String searchCode; + private String searchName; + private String searchId; + private String searchIsShow; +} diff --git a/src/main/java/com/mgm/mcrm/appsetting/dtos/RoomQueryRequest.java b/src/main/java/com/mgm/mcrm/appsetting/dtos/RoomQueryRequest.java new file mode 100644 index 0000000..dca350f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/appsetting/dtos/RoomQueryRequest.java @@ -0,0 +1,14 @@ +package com.mgm.mcrm.appsetting.dtos; + +import com.mgm.mcrm.common.dtos.BaseQueryRequest; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.commons.lang3.StringUtils; + +@EqualsAndHashCode(callSuper = true) +@Data +public class RoomQueryRequest extends BaseQueryRequest { + private String searchName; + private Long searchId; + private Long propertyId; +} diff --git a/src/main/java/com/mgm/mcrm/appsetting/dtos/RoomTypeQueryRequest.java b/src/main/java/com/mgm/mcrm/appsetting/dtos/RoomTypeQueryRequest.java new file mode 100644 index 0000000..e4b2eab --- /dev/null +++ b/src/main/java/com/mgm/mcrm/appsetting/dtos/RoomTypeQueryRequest.java @@ -0,0 +1,11 @@ +package com.mgm.mcrm.appsetting.dtos; + +import com.mgm.mcrm.common.dtos.BaseQueryRequest; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class RoomTypeQueryRequest extends BaseQueryRequest { + private String searchName; +} diff --git a/src/main/java/com/mgm/mcrm/appsetting/dtos/SysSettingQueryRequest.java b/src/main/java/com/mgm/mcrm/appsetting/dtos/SysSettingQueryRequest.java new file mode 100644 index 0000000..4934ab6 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/appsetting/dtos/SysSettingQueryRequest.java @@ -0,0 +1,12 @@ +package com.mgm.mcrm.appsetting.dtos; + + +import com.mgm.mcrm.common.dtos.BaseQueryRequest; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class SysSettingQueryRequest extends BaseQueryRequest { + private String key; +} diff --git a/src/main/java/com/mgm/mcrm/appsetting/dtos/WaitlistBookingQueryRequest.java b/src/main/java/com/mgm/mcrm/appsetting/dtos/WaitlistBookingQueryRequest.java new file mode 100644 index 0000000..3565f3c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/appsetting/dtos/WaitlistBookingQueryRequest.java @@ -0,0 +1,16 @@ +package com.mgm.mcrm.appsetting.dtos; + +import com.mgm.mcrm.common.dtos.BaseQueryRequest; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class WaitlistBookingQueryRequest extends BaseQueryRequest { + private String checkoutDate; + private String checkinDate; + private String playerId; + private String userId; + private String propertyId; + private String roomId; +} diff --git a/src/main/java/com/mgm/mcrm/appsetting/models/CfgSettings.java b/src/main/java/com/mgm/mcrm/appsetting/models/CfgSettings.java new file mode 100644 index 0000000..474c2b8 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/appsetting/models/CfgSettings.java @@ -0,0 +1,33 @@ +package com.mgm.mcrm.appsetting.models; + +import java.io.Serializable; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +@Entity +@Table(name="cfg_settings")// +public class CfgSettings implements Serializable { + + @Id + @Column(name="keys") + private String keys; + @Column(name="key_values") + private String keyValues; + + public String getKeys() { + return keys; + } + public void setKeys(String keys) { + this.keys = keys; + } + public String getKeyValues() { + return keyValues; + } + public void setKeyValues(String keyValues) { + this.keyValues = keyValues; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/appsetting/models/SysSetting.java b/src/main/java/com/mgm/mcrm/appsetting/models/SysSetting.java new file mode 100644 index 0000000..4403b89 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/appsetting/models/SysSetting.java @@ -0,0 +1,42 @@ +package com.mgm.mcrm.appsetting.models; + +import java.io.Serializable; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.persistence.Transient; + +@Entity +@Table(name="sys_settings") +public class SysSetting implements Serializable { + //fields in table + @Id + @Column(name="setting_key") + private String settingKey; + @Column(name="setting_value") + private String settingValue; + @Transient + private boolean internalNetwork=false; + + public String getSettingKey() { + return settingKey; + } + public void setSettingKey(String settingKey) { + this.settingKey = settingKey; + } + public String getSettingValue() { + return settingValue; + } + public void setSettingValue(String settingValue) { + this.settingValue = settingValue; + } + public boolean isInternalNetwork() { + return internalNetwork; + } + public void setInternalNetwork(boolean internalNetwork) { + this.internalNetwork = internalNetwork; + } + +} diff --git a/src/main/java/com/mgm/mcrm/appsetting/repositories/SettingDao.java b/src/main/java/com/mgm/mcrm/appsetting/repositories/SettingDao.java new file mode 100644 index 0000000..edcac68 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/appsetting/repositories/SettingDao.java @@ -0,0 +1,10 @@ +package com.mgm.mcrm.appsetting.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import com.mgm.mcrm.appsetting.models.CfgSettings; + +public interface SettingDao extends JpaRepository { + @Query(value = "select * from cfg_settings with (nolock) where keys = ?1",nativeQuery=true) + CfgSettings getByKeys(String keys); +} diff --git a/src/main/java/com/mgm/mcrm/appsetting/repositories/SysSettingDao.java b/src/main/java/com/mgm/mcrm/appsetting/repositories/SysSettingDao.java new file mode 100644 index 0000000..747913d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/appsetting/repositories/SysSettingDao.java @@ -0,0 +1,20 @@ +package com.mgm.mcrm.appsetting.repositories; + +import java.util.List; + +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import com.mgm.mcrm.appsetting.models.SysSetting; + + +public interface SysSettingDao extends JpaRepository { + + @Query(value="select * from sys_settings where setting_key=?1",nativeQuery=true) + SysSetting getBySettingKey(String key); + + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); +} diff --git a/src/main/java/com/mgm/mcrm/appsetting/services/ConfigService.java b/src/main/java/com/mgm/mcrm/appsetting/services/ConfigService.java new file mode 100644 index 0000000..61d5b56 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/appsetting/services/ConfigService.java @@ -0,0 +1,719 @@ +package com.mgm.mcrm.appsetting.services; + +import java.time.LocalDateTime; +import java.util.*; + +import com.mgm.mcrm.allotment.models.*; +import com.mgm.mcrm.allotment.repositories.RoomCriteriaDaylightDao; +import com.mgm.mcrm.appsetting.dtos.*; +import com.mgm.mcrm.basesetting.daylight.models.*; +import com.mgm.mcrm.basesetting.daylight.repositories.*; +import com.mgm.mcrm.booking.models.BookingsView; +import jakarta.annotation.Resource; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Root; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Sort; +import org.springframework.data.domain.Sort.Direction; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson.JSONObject; +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.basesetting.room.models.CfgBedTypeMapping; +import com.mgm.mcrm.booking.models.CfgBookingTypes; +import com.mgm.mcrm.basesetting.team.models.CfgOtherUserMapping; +import com.mgm.mcrm.basesetting.property.models.CfgProperties; +import com.mgm.mcrm.basesetting.room.models.CfgRoomFeatures; +import com.mgm.mcrm.basesetting.room.models.CfgRoomTypes; +import com.mgm.mcrm.basesetting.room.models.CfgRooms; +import com.mgm.mcrm.basesetting.room.models.CfgRoomsRoomTypes; +import com.mgm.mcrm.appsetting.models.CfgSettings; +import com.mgm.mcrm.common.utils.DaoUtil; +import com.mgm.mcrm.common.utils.DateTimeUtil; +import com.mgm.mcrm.common.constants.SysConstants; +import com.mgm.mcrm.basesetting.room.repositories.BedTypeMappingDao; +import com.mgm.mcrm.allotment.repositories.OtherAllotmentViewDao; +import com.mgm.mcrm.basesetting.team.repositories.OtherUserMappingDao; +import com.mgm.mcrm.basesetting.property.repositories.PropertyDao; +import com.mgm.mcrm.allotment.repositories.RoomCriteriaDao; +import com.mgm.mcrm.basesetting.room.repositories.RoomDao; +import com.mgm.mcrm.basesetting.room.repositories.RoomFeatureDao; +import com.mgm.mcrm.basesetting.room.repositories.RoomRoomTypeDao; +import com.mgm.mcrm.basesetting.room.repositories.RoomTypeDao; +import com.mgm.mcrm.appsetting.repositories.SettingDao; +import com.mgm.mcrm.booking.repositories.BookingDao; +import com.mgm.mcrm.booking.repositories.BookingTypeDao; +import com.mgm.mcrm.booking.repositories.BookingViewDao; +import com.mgm.mcrm.basesetting.room.repositories.BedTypeMappingDao.BedType; +import com.mgm.mcrm.booking.services.WaitlistBookingService; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class ConfigService { + + @Resource + private BookingDao bookingDao; + @Resource + private PropertyDao propertyDao; + @Resource + private RoomDao roomDao; + @Resource + private RoomTypeDao roomTypeDao; + @Resource + private BedTypeMappingDao bedTypeMappingDao; + @Resource + private RoomFeatureDao roomFeatureDao; + @Resource + private RoomCriteriaDao criteriaDao; + @Resource + private RoomCriteriaDaylightDao criteriaDaylightDao; + @Resource + private SettingDao settingDao; + @Resource + private BookingTypeDao bookingTypeDao; + @Resource + private DaylightViewDao daylightViewDao; + @Resource + private ExceptionDaylightViewDao exceptionDaylightViewDao; + @Resource + private ExceptionOperaViewDao exceptionOperaViewDao; + @Resource + private RoomRoomTypeDao roomRoomTypeDao; + @Resource + private BookingViewDao bookingViewDao; + @Resource + private WaitlistBookingService waitlistBookingService; + @Resource + private OperaViewDao operaViewDao; + @Resource + private BlockCodeDao blockCodesDao; + @Resource + private OtherUserMappingDao otherUserMappingDao; + @Autowired + private OtherAllotmentViewDao otherAllotmentDao; + + public List listProperty(PropertyQueryRequest queryFilter) { + Specification listSpec = (root, criteriaQuery, cb) -> { + List list = new ArrayList<>(); + // status=0 的记录不返回 + list.add(cb.notEqual(root.get("status"), 0)); + if(StringUtils.isNotBlank(queryFilter.getSearchCode())) { + list.add(cb.equal(root.get("code") , queryFilter.getSearchCode())); + } + if(StringUtils.isNotBlank(queryFilter.getSearchName())) { + list.add(cb.like(cb.upper(root.get("name")) , "%" + queryFilter.getSearchName().toUpperCase() + "%")); + } + if(StringUtils.isNotBlank(queryFilter.getSearchCategory())) { + list.add(cb.equal(root.get("category") , queryFilter.getSearchCategory())); + } + //-- + if(StringUtils.isNotBlank(queryFilter.getSearchId())) { + List searchIds = DaoUtil.parseMultipleFilter(queryFilter.getSearchId()); + if(searchIds.size()==1) { + list.add(cb.equal(root.get("id"), searchIds.getFirst())); + }else if(searchIds.size()>1) { + list.add(root.get("id").in(searchIds)); + } + } + + //-- + Predicate[] predicates = new Predicate[list.size()]; + criteriaQuery.where(list.toArray(predicates)); + return cb.and(list.toArray(predicates)); + }; + Sort sort = DaoUtil.buildSortByFilter( + queryFilter.getSortOrder(), + "category;sortOrder-asc" + ); + return propertyDao.findAll(listSpec,sort); + } + + public List listRoom(RoomQueryRequest queryFilter) { + Specification listSpec = (root, criteriaQuery, cb) -> { + List list = new ArrayList<>(); + if (queryFilter.getSearchId()!=null) { + list.add(cb.equal(root.get("id"), queryFilter.getSearchId())); + } + if (StringUtils.isNotBlank(queryFilter.getSearchName())) { + list.add(cb.like(cb.upper(root.get("name")), + "%" + queryFilter.getSearchName().toUpperCase() + "%")); + } + if(queryFilter.getPropertyId()!=null && queryFilter.getPropertyId()!=0) { + list.add(cb.equal(root.get("propertyId"), queryFilter.getPropertyId())); + } + Predicate[] predicates = new Predicate[list.size()]; + criteriaQuery.where(list.toArray(predicates)); + return cb.and(list.toArray(predicates)); + }; + Sort sort = DaoUtil.buildSortByFilter(queryFilter.getSortOrder(), "id"); + return roomDao.findAll(listSpec,sort); + } + + public List listRoomType(RoomTypeQueryRequest queryFilter) { + Specification listSpec = (root, criteriaQuery, cb) -> { + List list = new ArrayList<>(); + if (StringUtils.isNotBlank(queryFilter.getSearchName())) { + list.add(cb.like(cb.upper(root.get("name")), + "%" + queryFilter.getSearchName().toUpperCase() + "%")); + } + Predicate[] predicates = new Predicate[list.size()]; + criteriaQuery.where(list.toArray(predicates)); + return cb.and(list.toArray(predicates)); + }; + Sort sort = DaoUtil.buildSortByFilter(queryFilter.getSortOrder(), "id"); + return roomTypeDao.findAll(listSpec,sort); + } + + public List listBedType(BedTypeQueryRequest queryFilter) { + Long propertyId = queryFilter.getPropertyId(); + Long roomId = queryFilter.getRoomId(); + return bedTypeMappingDao.queryByPropertyIdAndRoomId(propertyId, roomId); + } + + public List listRoomFeature(RoomFeatureQueryRequest queryFilter) { + Specification listSpec = (root, criteriaQuery, cb) -> { + List list = new ArrayList<>(); + String category = queryFilter.getCategory(); + list.add( + cb.or( + cb.equal(root.get("category"), category) + ) + ); + + if(StringUtils.isNotBlank(queryFilter.getSearchCode())) { + list.add(cb.equal(root.get("code") , queryFilter.getSearchCode())); + } + if(StringUtils.isNotBlank(queryFilter.getSearchName())) { + list.add(cb.like(cb.upper(root.get("description")) , "%" + queryFilter.getSearchName().toUpperCase() + "%")); + } + //-- + if(StringUtils.isNotBlank(queryFilter.getSearchId())) { + List searchIds = DaoUtil.parseMultipleFilter(queryFilter.getSearchId()); + if(searchIds.size()==1) { + list.add(cb.equal(root.get("id"), searchIds.getFirst())); + }else if(searchIds.size()>1) { + list.add(root.get("id").in(searchIds)); + } + } + if(StringUtils.isNotBlank(queryFilter.getSearchIsShow())) { + list.add(cb.equal(root.get("showInBooking") , queryFilter.getSearchIsShow())); + } + //-- + Predicate[] predicates = new Predicate[list.size()]; + criteriaQuery.where(list.toArray(predicates)); + return cb.and(list.toArray(predicates)); + }; + Sort sort = DaoUtil.buildSortByFilter(queryFilter.getSortOrder(), "id"); + return roomFeatureDao.findAll(listSpec,sort); + } + + public Map listRoomCriteriaCalendar(RoomCriteriaQueryRequest queryParas) throws Exception { + Map resultList = new HashMap<>(); + Long bookingTypeId = queryParas.getBookingTypeId(); + Long blockId = queryParas.getBlockId(); + Long segmentId = queryParas.getSegmentId(); + Long propertyId = queryParas.getPropertyId(); + Long roomId = queryParas.getRoomId(); + boolean coded = queryParas.isCoded(); + String userId = queryParas.getUserId(); + String userName = queryParas.getUserName(); + String playerId = queryParas.getPlayerId(); + Long sectionId = queryParas.getSectionId(); + Long bedTypeMasterGroupId = queryParas.getBedTypeId(); + + //check opera criteria or other criteria + CfgProperties property = propertyDao.getById(propertyId); + CfgRooms room = roomDao.findById(roomId); + boolean isOpera = false; + boolean isWaitlist = false; + boolean isDaylight = false; + if(Strings.CS.equals(property.getCategory(), "OPERA")) isOpera = true; + if(Strings.CS.equals(property.getCategory(), "DAYLIGHT")) isDaylight = true; + if(room.getForWaitlist() != null && room.getForWaitlist()==1&&room.getForBooking()==0) isWaitlist = true; + + if(isOpera||isWaitlist) { + resultList = getOperaCriteria( blockId,sectionId, bookingTypeId, propertyId, roomId, bedTypeMasterGroupId,userId); + } else if (isDaylight) { + resultList = getDaylightCriteria( blockId,sectionId, bookingTypeId, propertyId, roomId, bedTypeMasterGroupId,userId); + } else { + resultList = getOtherCriteria( segmentId, sectionId, bookingTypeId, propertyId, roomId); + } + if(!resultList.isEmpty()) { + checkCriteriaBooking(resultList, playerId, userId, userName); + } + + return resultList; + } + + public Map getDaylightCriteria(Long blockCodeId,Long sectionId,Long bookingTypeId,Long propertyId,Long roomId,Long bedTypeMasterGroupId,String userId) throws Exception{ + log.info("[getDaylightCriteria] Input params: blockCodeId={}, sectionId={}, bookingTypeId={}, propertyId={}, roomId={}, bedTypeMasterGroupId={}, userId={}", blockCodeId, sectionId, bookingTypeId, propertyId, roomId, bedTypeMasterGroupId, userId); + Long roomTypeId = null; + List roomIds = new ArrayList<>(); + roomIds.add(roomId); + + Map resultList = new HashMap<>(); +// Date today = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd"); + LocalDateTime today = LocalDateTime.now(); + String maxDay = settingDao.getByKeys(SysConstants.MAX_ADVANCE_BOOKING_DAYS).getKeyValues(); +// Date endDate = DateTimeUtil.addDay(today, Integer.valueOf(maxDay)); + LocalDateTime endDate = today.plusDays(Integer.parseInt(maxDay)); + today = today.minusDays(1); + + List teamDaylight = new ArrayList<>(); + List eDaylightViewList = new ArrayList<>(); + // 如果有BedTypeId根据BedTypeId拿到RoomTypeId List后随机,否则按RoomId + List roomTypes; + List bedTypes; + + if(blockCodeId==null) { + log.info("[getDaylightCriteria] Input blockCodeId is null, will determine via daylightView/exceptionDaylightView"); + if(bedTypeMasterGroupId==null) { + roomTypes = roomRoomTypeDao.queryByRoomId(roomId);// 该方法可能要改成一个view的直接拿到RoomTypeId和RoomTypeCode + if(roomTypes!=null && !roomTypes.isEmpty()) { + roomTypeId = roomTypes.get(new Random().nextInt(roomTypes.size())).getRoomTypeId(); +// roomTypeId = roomTypes.get(0).getRoomTypeId(); + } + }else { + bedTypes = bedTypeMappingDao.queryByMasterGroupId(bedTypeMasterGroupId);// 该方法可能要改成一个view的直接拿到RoomTypeId和RoomTypeCode + if(bedTypes!=null && !bedTypes.isEmpty()) { + roomTypeId = Long.valueOf(bedTypes.get(new Random().nextInt(bedTypes.size())).getRoomTypeId()); +// roomTypeId = Long.valueOf(bedTypes.get(0).getRoomTypeId()); + } + } + log.info("[getDaylightCriteria] roomTypeId determined, roomTypeId={}, bedTypeMasterGroupId={}", roomTypeId, bedTypeMasterGroupId); + //先从exception opera mapping拿,没有再去 opera mapping拿 + List eDLs = + exceptionDaylightViewDao.findByUserIdLikeAndPropertyIdAndBookingTypeId("%"+userId+"%",propertyId, bookingTypeId); + log.info("[getDaylightCriteria] exceptionDaylightView query done, userId={}, propertyId={}, bookingTypeId={}, resultCount={}", userId, propertyId, bookingTypeId, eDLs.size()); + if(!eDLs.isEmpty()) { + for(CfgExceptionDaylightView o :eDLs) { + for(CfgRoomTypes r :o.getDaylightRoomType()) { + if(Objects.equals(r.getId(), roomTypeId)) { + eDaylightViewList.add(o); + } + } + } + } + log.info("[getDaylightCriteria] exceptionDaylightView filtered by roomTypeId, matchCount={}, roomTypeId={}", eDaylightViewList.size(), roomTypeId); + // 筛选出符合条件的opear mapping记录,没有Opera mapping要提示前端配置 + + List dLs = daylightViewDao.findBySectionIdAndPropertyIdAndBookingTypeId(sectionId,propertyId, bookingTypeId); + log.info("[getDaylightCriteria] daylightView query done, sectionId={}, propertyId={}, bookingTypeId={}, resultCount={}", sectionId, propertyId, bookingTypeId, dLs.size()); + for(CfgDaylightView o :dLs) { + for(CfgRoomTypes r :o.getDaylightRoomType()) { + if(Objects.equals(r.getId(), roomTypeId)) { + teamDaylight.add(o); + } + } + } + log.info("[getDaylightCriteria] daylightView filtered by roomTypeId, matchCount={}, roomTypeId={}", teamDaylight.size(), roomTypeId); + if(!eDaylightViewList.isEmpty()) { + blockCodeId = eDaylightViewList.getFirst().getBlockCodeId(); + log.info("[getDaylightCriteria] Using exceptionDaylightView blockCodeId={}", blockCodeId); + }else if(!teamDaylight.isEmpty()) { + blockCodeId = teamDaylight.getFirst().getBlockCodeId(); + log.info("[getDaylightCriteria] Using daylightView blockCodeId={}", blockCodeId); + }else { + log.warn("[getDaylightCriteria] Neither exceptionDaylightView nor daylightView matched, blockCodeId will be null"); + } + } else { + log.info("[getDaylightCriteria] Input blockCodeId provided directly, blockCodeId={}", blockCodeId); + } + + log.info("[getDaylightCriteria] Final blockCodeId={}, availability date range: {} ~ {}", blockCodeId, today.toLocalDate(), endDate.toLocalDate()); + // Daylight:渠道行存的是 block_code_id,与视图/入参中的 blockCodeId 一致,无需再解析 cfg_block_codes + List criterias = criteriaDaylightDao.findByRoomIdInAndPropertyIdAndBookDateBetween(roomIds,propertyId,today, endDate); + log.info("[getDaylightCriteria] Availability query done, dayCount={}", criterias.size()); + for(CfgRoomCriteriasDaylight c:criterias) { + JSONObject res = new JSONObject(); + String bookDate = DateTimeUtil.getDateByFormat(c.getBookDate(),"yyyy-MM-dd"); + res.put("bookDate",bookDate); + res.put("isWaitlist",c.getIsWaitlist()); + res.put("sharer",c.getSharer()); + CfgAppChannelDaylight channel = new CfgAppChannelDaylight(); + Set channels = c.getChannels(); + for(CfgAppChannelDaylight a:channels) { + if(Objects.equals(a.getBlockCodeId(), blockCodeId)) channel = a; + } + res.put("available",channel.getAvailable()); + resultList.put(bookDate ,res); + } + + return resultList; + } + + public Map getOperaCriteria(Long blockCodeId,Long sectionId,Long bookingTypeId,Long propertyId,Long roomId,Long bedTypeMasterGroupId,String userId) throws Exception{ + log.info("[getOperaCriteria] Input params: blockCodeId={}, sectionId={}, bookingTypeId={}, propertyId={}, roomId={}, bedTypeMasterGroupId={}, userId={}", blockCodeId, sectionId, bookingTypeId, propertyId, roomId, bedTypeMasterGroupId, userId); + Long roomTypeId = null; + List roomIds = new ArrayList<>(); + roomIds.add(roomId); + + Map resultList = new HashMap<>(); + Date today = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd"); + String maxDay = settingDao.getByKeys(SysConstants.MAX_ADVANCE_BOOKING_DAYS).getKeyValues(); + Date endDate = DateTimeUtil.addDay(today, Integer.valueOf(maxDay)); + + List teamOpera = new ArrayList<>(); + List exceptionOpera = new ArrayList<>(); + // 如果有BedTypeId根据BedTypeId拿到RoomTypeId List后随机,否则按RoomId + List roomTypes; + List bedTypes; + Long blockId = null; + if(blockCodeId==null) { + log.info("[getOperaCriteria] Input blockCodeId is null, will determine via operaView/exceptionOperaView"); + if(bedTypeMasterGroupId==null) { + roomTypes = roomRoomTypeDao.queryByRoomId(roomId);// 该方法可能要改成一个view的直接拿到RoomTypeId和RoomTypeCode + if(roomTypes!=null && !roomTypes.isEmpty()) { + // 暂时先拿第一个,这里要改成随机算法。拿roomType用得少就用那个要实现平均分配 + roomTypeId = roomTypes.get(0).getRoomTypeId(); + } + }else { + bedTypes = bedTypeMappingDao.queryByMasterGroupId(bedTypeMasterGroupId);// 该方法可能要改成一个view的直接拿到RoomTypeId和RoomTypeCode + if(bedTypes!=null && !bedTypes.isEmpty()) { + // 暂时先拿第一个,这里要改成随机算法。拿roomType用得少就用那个要实现平均分配 + roomTypeId = Long.valueOf(bedTypes.get(0).getRoomTypeId()); + } + } + log.info("[getOperaCriteria] roomTypeId determined, roomTypeId={}, bedTypeMasterGroupId={}", roomTypeId, bedTypeMasterGroupId); + //先从exception opera mapping拿,没有再去 opera mapping拿 + List eoperas = + exceptionOperaViewDao.findByUserIdLikeAndPropertyIdAndBookingTypeId("%"+userId+"%",propertyId, bookingTypeId); + log.info("[getOperaCriteria] exceptionOperaView query done, userId={}, propertyId={}, bookingTypeId={}, resultCount={}", userId, propertyId, bookingTypeId, eoperas.size()); + if(!eoperas.isEmpty()) { + for(CfgExceptionOperaView o :eoperas) { + for(CfgRoomTypes r :o.getOperaRoomType()) { + if(Objects.equals(r.getId(), roomTypeId)) { + exceptionOpera.add(o); + } + } + } + } + log.info("[getOperaCriteria] exceptionOperaView filtered by roomTypeId, matchCount={}, roomTypeId={}", exceptionOpera.size(), roomTypeId); + // 筛选出符合条件的opear mapping记录,没有Opera mapping要提示前端配置 + List operas = operaViewDao.findBySectionIdAndPropertyIdAndBookingTypeId(sectionId,propertyId, bookingTypeId); + log.info("[getOperaCriteria] operaView query done, sectionId={}, propertyId={}, bookingTypeId={}, resultCount={}", sectionId, propertyId, bookingTypeId, operas.size()); + for(CfgOperaView o :operas) { + for(CfgRoomTypes r :o.getOperaRoomType()) { + if(Objects.equals(r.getId(), roomTypeId)) { + teamOpera.add(o); + } + } + } + log.info("[getOperaCriteria] operaView filtered by roomTypeId, matchCount={}, roomTypeId={}", teamOpera.size(), roomTypeId); + if(!exceptionOpera.isEmpty()) { + blockCodeId = exceptionOpera.getFirst().getBlockCodeId(); + log.info("[getOperaCriteria] Using exceptionOperaView blockCodeId={}", blockCodeId); + }else if(!teamOpera.isEmpty()) { + blockCodeId = teamOpera.getFirst().getBlockCodeId(); + log.info("[getOperaCriteria] Using operaView blockCodeId={}", blockCodeId); + }else { + log.warn("[getOperaCriteria] Neither exceptionOperaView nor operaView matched, blockCodeId will be null"); + } + + if(blockCodeId!=null) { + CfgBlockCodes blockCode = blockCodesDao.findById(blockCodeId).orElse(null); + if(blockCode!=null) + blockId = blockCode.getBlockId(); + log.info("[getOperaCriteria] Resolved blockId from blockCodeId, blockCodeId={}, blockId={}", blockCodeId, blockId); + } + + } else { + blockId = blockCodeId; + log.info("[getOperaCriteria] Input blockCodeId provided directly, blockCodeId={}, blockId={}", blockCodeId, blockId); + } + + + log.info("[getOperaCriteria] Final blockCodeId={}, blockId={}, availability date range: {} ~ {}", blockCodeId, blockId, DateTimeUtil.getDateByFormat(today,"yyyy-MM-dd"), DateTimeUtil.getDateByFormat(endDate,"yyyy-MM-dd")); + List criterias = criteriaDao.findByRoomIdInAndPropertyIdAndBookDateBetween(roomIds,propertyId,today,endDate); + log.info("[getOperaCriteria] Availability query done, dayCount={}", criterias.size()); + for(CfgRoomCriterias c:criterias) { + JSONObject res = new JSONObject(); + String bookDate = DateTimeUtil.getDateByFormat(c.getBookDate(),"yyyy-MM-dd"); + res.put("bookDate",bookDate); + res.put("isWaitlist",c.getIsWaitlist()); + res.put("sharer",c.getSharer()); + CfgAppChannel channel = new CfgAppChannel(); + Set channels = c.getChannels(); + for(CfgAppChannel a:channels) { + if(Objects.equals(a.getBlockId(), blockId)) channel = a; + } + res.put("available",channel.getAvailable()); + resultList.put(bookDate ,res); + } + + return resultList; + } + + private void addDateToMap(Map resultMap, String date, + Integer im, Integer reserved, Integer sharer, + Integer staying, Integer available, Integer protection, + Integer isWaitlist, Integer massStandard) { + JSONObject dateObject = new JSONObject(); + dateObject.put("bookDate", date); + + if (im != null) dateObject.put("im", im); + if (reserved != null) dateObject.put("reserved", reserved); + if (sharer != null) dateObject.put("sharer", sharer); + if (staying != null) dateObject.put("staying", 0); + if (available != null) dateObject.put("available", available); + if (protection != null) dateObject.put("protection", protection); + if (isWaitlist != null) dateObject.put("isWaitlist", isWaitlist); + if (massStandard != null) dateObject.put("massStandard", massStandard); + + resultMap.put(date, dateObject); + } + + + public Map getOtherCriteria(Long segmentId,Long teamId,Long bookingTypeId,Long propertyId,Long roomId) throws Exception{ + Long roomTypeId = null; + List roomIds = new ArrayList<>(); + roomIds.add(roomId); + Date today = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd"); + String maxDay = settingDao.getByKeys(SysConstants.MAX_ADVANCE_BOOKING_DAYS).getKeyValues(); + Date endDate = DateTimeUtil.addDay(today, Integer.valueOf(maxDay)); + + Map resultList = new HashMap<>(); + + + List userMappingList = new ArrayList<>(); + CfgOtherUserMapping userMapping = new CfgOtherUserMapping(); + + // 如果有BedTypeId根据BedTypeId拿到RoomTypeId List后随机,否则按RoomId + List roomTypes = new ArrayList<>(); + List bedTypes = new ArrayList<>(); + + if(segmentId==null) { + // 筛选出符合条件的 mapping记录 + userMappingList = otherUserMappingDao.findBySectionIdAndPropertyIdAndBookingTypeId(teamId,propertyId,Long.valueOf(bookingTypeId)); + + if(!userMappingList.isEmpty()) { + segmentId = userMappingList.getFirst().getSegmentId(); + } + } + + List criterias = otherAllotmentDao.findByRoomIdInAndPropertyIdAndBookDateBetween(roomIds,propertyId,today,endDate); + for(CfgOtherAllotmentView c:criterias) { + JSONObject res = new JSONObject(); + String bookDate = DateTimeUtil.getDateByFormat(c.getBookDate(),"yyyy-MM-dd"); + res.put("bookDate",bookDate); + res.put("isWaitlist",c.getIsWaitlist()); + res.put("sharer",c.getSharer()); + CfgOtherAppChannel channel = new CfgOtherAppChannel(); + Set channels = c.getChannels(); + for(CfgOtherAppChannel a:channels) { + if(a.getSegmentId()!=null&&segmentId!=null) { + if(Objects.equals(a.getSegmentId(), segmentId)) channel = a; + } + + } + + res.put("available",channel.getAvailable()); + resultList.put(bookDate ,res); + } + + return resultList; + } + + private Map checkCriteriaBooking(Map resultList,String playerId,String userId,String userName) throws Exception{ + Date today = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd"); + String maxDay = settingDao.getByKeys(SysConstants.MAX_ADVANCE_BOOKING_DAYS).getKeyValues(); + boolean enableProtection = Strings.CS.equals("1", settingDao.getByKeys(SysConstants.PROTECT_PERIOD_ENABLE).getKeyValues())?true:false; + String checkinProtection = settingDao.getByKeys(SysConstants.PROTECTION_PERIOD_CHECKIN).getKeyValues(); + String checkoutProtection = settingDao.getByKeys(SysConstants.PROTECTION_PERIOD_CHECKOUT).getKeyValues(); + Date endDate = DateTimeUtil.addDay(today, Integer.valueOf(maxDay)); + + List bookingList = bookingViewDao.getCalendarBooking(endDate, playerId); + + Set protectionPeriod = new HashSet(); + for(BookingsView book:bookingList) { + if(StringUtils.isEmpty(book.getLastOperaStatus())|| + Strings.CS.equals(book.getLastOperaStatus(), "DUE_IN")|| + Strings.CS.equals(book.getLastOperaStatus(), "RESERVED")|| + Strings.CS.equals(book.getLastOperaStatus(), "CHECKED_IN")) { + // no coded + boolean differentUser = true; + if(!StringUtils.isEmpty(book.getCreatedBy())) { + differentUser = !Strings.CS.equals(book.getCreatedBy(), userId); + }else if(!StringUtils.isEmpty(book.getCreatedByName())) { + differentUser = !Strings.CS.equals(book.getCreatedByName(), userName); + } + if(enableProtection&&differentUser) { + if(Integer.valueOf(checkinProtection)>=0) { + for(int q=0;q<=Integer.valueOf(checkinProtection);q++) { + Date protectCheckin = DateTimeUtil.addDay( book.getCheckinDate(), Integer.valueOf(q)); + protectionPeriod.add(protectCheckin); + } + }else { + for(int q=0;q>=Integer.valueOf(checkinProtection);q--) { + Date protectCheckin = DateTimeUtil.addDay( book.getCheckinDate(), Integer.valueOf(q)); + protectionPeriod.add(protectCheckin); + } + } + //change check out date to check in + if(Integer.valueOf(checkoutProtection)>=0) { + for(int q=0;q<=Integer.valueOf(checkoutProtection);q++) { + Date protectCheckout = DateTimeUtil.addDay( book.getCheckinDate(), Integer.valueOf(q)); + protectionPeriod.add(protectCheckout); + } + }else { + for(int q=0;q>=Integer.valueOf(checkoutProtection);q--) { + Date protectCheckout = DateTimeUtil.addDay( book.getCheckinDate(), Integer.valueOf(q)); + protectionPeriod.add(protectCheckout); + } + } + } + + Date checkInDate = book.getCheckinDate(); + Date checkOutDate = book.getCheckoutDate(); + + while(checkInDate.getTime() listRoomSetting() { + Sort sort = Sort.by(Direction.ASC, "keys"); + return settingDao.findAll(sort); + } + + public HashSet listRoomCriteriaAvailableRoom(AvailableRoomQueryRequest queryParas) { + HashSet resultList = new HashSet<>(); + List selectDate = queryParas.getSelectDate(); + Date checkinDate = DateTimeUtil.getDateFromString(String.valueOf(selectDate.getFirst()), "yyyy-MM-dd"); + Date checkoutDate = DateTimeUtil.getDateFromString(String.valueOf(selectDate.get(1)), "yyyy-MM-dd"); + String diffDate = DateTimeUtil.getDiffDate(checkinDate, checkoutDate, "day"); + Long blockId = queryParas.getBlockId(); + Long propertyId = queryParas.getPropertyId(); + Long roomId = queryParas.getRoomId(); + List roomIds = new ArrayList(); + roomIds.add(roomId); + List criterias = criteriaDao.findByRoomIdNotInAndPropertyIdAndBookDateBetween(roomIds,propertyId,checkinDate,checkoutDate); + HashMap> criteriaMap= new HashMap<>(); + for(CfgRoomCriterias c:criterias) { + if(c.getIsWaitlist()==0) { + CfgAppChannel channel = new CfgAppChannel(); + Set channels = c.getChannels(); + for(CfgAppChannel a:channels) { + if(blockId.equals(a.getBlockId())) channel = a; + } + if(channel.getAvailable()>0) { + String roomName = c.getRoom().getName(); + if(criteriaMap.containsKey(roomName)) { + List roomList = criteriaMap.get(roomName); + roomList.add(roomName); + criteriaMap.put(roomName, roomList); + }else { + List roomList = new ArrayList<>(); + roomList.add(roomName); + criteriaMap.put(roomName, roomList); + } + } + } + + } + criteriaMap.forEach((key, value) -> { + if((Integer.parseInt(diffDate)+1)==value.size()) { + resultList.add(key); + } + }); + return resultList; + } + + public List listIsExtendBooking(ExtendBookingQueryRequest queryParas) { + List bookingList = new ArrayList<>(); + Date checkoutDate = DateTimeUtil.getDateFromString(queryParas.getCheckoutDate(), "yyyy-MM-dd"); + Date checkinDate = DateTimeUtil.getDateFromString(queryParas.getCheckinDate(), "yyyy-MM-dd"); + String playerId = queryParas.getPlayerId(); + String userId = queryParas.getUserId(); + String propertyId = queryParas.getPropertyId(); + String roomId = queryParas.getRoomId(); + + bookingList = bookingDao.getExtendBooking(checkoutDate,playerId,userId,propertyId,roomId); + return bookingList; + } + + public List getWaitlistBooking(WaitlistBookingQueryRequest queryParas) throws Exception { + List bookingList = new ArrayList<>(); + Date checkoutDate = DateTimeUtil.getDateFromString(queryParas.getCheckoutDate(), "yyyy-MM-dd"); + Date checkinDate = DateTimeUtil.getDateFromString(queryParas.getCheckinDate(), "yyyy-MM-dd"); + String playerId = queryParas.getPlayerId(); + String userId = queryParas.getUserId(); +// String propertyId = String.valueOf(queryParas.get("propertyId")); +// String roomId = String.valueOf(queryParas.get("roomId")); + + List dbBookingList = bookingDao.getWaitlistBooking(checkinDate,checkoutDate,playerId,userId); + List waitlistResult = waitlistBookingService.getBookingsByPlayer(playerId); + + for(Bookings b :dbBookingList) { + for(BookingsView bv:waitlistResult) { + if(b.getId().equals(bv.getId())) { + bookingList.add(b); + } + } + } + + return bookingList; + } + + public List listAllBookingType() { + return bookingTypeDao.findAll(); + } + + +} diff --git a/src/main/java/com/mgm/mcrm/appsetting/services/SettingService.java b/src/main/java/com/mgm/mcrm/appsetting/services/SettingService.java new file mode 100644 index 0000000..43e9c81 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/appsetting/services/SettingService.java @@ -0,0 +1,28 @@ +package com.mgm.mcrm.appsetting.services; + +import java.util.List; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import com.mgm.mcrm.appsetting.models.CfgSettings; +import com.mgm.mcrm.appsetting.repositories.SettingDao; + +@Service +public class SettingService { + + @Resource + private SettingDao settingDao; + + public CfgSettings getSettingByKey(String key) { + CfgSettings setting = null; + setting = settingDao.getByKeys(key); + return setting; + } + + public List getSysSettingsAll() { + List list = settingDao.findAll(); + return list; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/appsetting/services/SysSettingService.java b/src/main/java/com/mgm/mcrm/appsetting/services/SysSettingService.java new file mode 100644 index 0000000..edb37db --- /dev/null +++ b/src/main/java/com/mgm/mcrm/appsetting/services/SysSettingService.java @@ -0,0 +1,45 @@ +package com.mgm.mcrm.appsetting.services; + +import java.util.List; + +import jakarta.annotation.Resource; +import org.apache.commons.lang3.Strings; +import org.springframework.stereotype.Service; + +import com.mgm.mcrm.appsetting.models.SysSetting; +import com.mgm.mcrm.appsetting.repositories.SysSettingDao; + +@Service +public class SysSettingService { + + @Resource + private SysSettingDao sysSettingDao; + + public SysSetting getSysSettingByKey(String key) { + + return sysSettingDao.getBySettingKey(key); + } + + public List getSysSettingsAll() { + return sysSettingDao.findAll(); + } + + public SysSetting save(SysSetting obj) { + return sysSettingDao.save(obj); + } + + public boolean isAPPMock() { + SysSetting sysSetting = sysSettingDao.getBySettingKey("APP_MOCK"); + return Strings.CS.equals(sysSetting.getSettingValue(), "1"); + } + + public boolean isMockReplicate() { + SysSetting sysSetting = sysSettingDao.getBySettingKey("APP_MOCK_REPLICATE"); + return Strings.CS.equals(sysSetting.getSettingValue(), "1"); + } + + public boolean isDBDbugLog() { + SysSetting sysSetting = sysSettingDao.getBySettingKey("DB_DEBUG_LOG"); + return Strings.CS.equals(sysSetting.getSettingValue(), "1"); + } +} diff --git a/src/main/java/com/mgm/mcrm/authorization/controllers/MobileLoginController.java b/src/main/java/com/mgm/mcrm/authorization/controllers/MobileLoginController.java new file mode 100644 index 0000000..333f7a8 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/controllers/MobileLoginController.java @@ -0,0 +1,408 @@ +package com.mgm.mcrm.authorization.controllers; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; + +import com.mgm.mcrm.authorization.dtos.*; +import com.mgm.mcrm.authorization.models.SysGroup; +import com.mgm.mcrm.authorization.models.SysRouterPermission; +import com.mgm.mcrm.authorization.models.Token; +import com.mgm.mcrm.authorization.services.*; +import com.mgm.mcrm.authorization.utils.JwtTokenUtil; +import com.mgm.mcrm.basesetting.team.models.CfgSections; +import com.mgm.mcrm.basesetting.team.repositories.SectionDao; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.common.utils.*; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import jakarta.validation.Valid; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.util.Base64Util; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import com.auth0.jwt.JWT; + +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.constants.SysConstants; +import com.mgm.mcrm.authorization.repositories.SysGroupDao; +import com.mgm.mcrm.appsetting.models.CfgSettings; +import com.mgm.mcrm.common.dtos.mgm_api.CheckApproverResult; +import com.mgm.mcrm.common.dtos.mgm_api.UserInfoApiRecord; +import com.mgm.mcrm.appsetting.services.SettingService; + +@Tag(name = "Authorization", description = "APIs for Authorization functions") +@RestController +@CrossOrigin(origins = "*") +@RequestMapping("/api") +public class MobileLoginController { + @Resource + private MgmUserService mgmUserService; + @Resource + private AuthorizationService authService; + @Resource + private UserTokenService userTokenService; + @Resource + private SettingService settingService; + @Resource + private SysGroupDao sysGroupDao; + @Resource + private SectionDao sectionDao; + @Resource + private SysGroupPermissionService sysGroupPermissionService; + + // 该方法用于模拟sso登录,生产环境下不适用 + @RequestMapping(value = "/app/sso/mock_user_sso_login", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity mockupUserLogin(HttpServletRequest request, HttpServletResponse response, @RequestBody(required=true) @Valid AccountLoginRequest accountLoginRequest) throws IOException { + AccountLoginResponse result = new AccountLoginResponse(); + String userId = accountLoginRequest.getUserId(); + String password = accountLoginRequest.getCredential(); + String propertyCode = accountLoginRequest.getPropertyCode(); + String accessIp = NetworkUtil.getClientIpAddr(request); + boolean isInternal = NetworkUtil.isMatchInternal(accessIp); + String remoteAddr = request.getRemoteAddr(); + boolean allowIP = NetworkUtil.isRequestFromTrustedSource(request); + if(!allowIP) { + LogUtil.warn(MobileLoginController.class, "IP of ["+remoteAddr+"] is not valid proxy IP "); + response.sendError(401, "Invalid Forward IP"); + } + if(!isInternal){ + LogUtil.info(MobileLoginController.class, "[preHandle] getRealIp:" + accessIp); + CfgSettings macauIpSetting = settingService.getSettingByKey(SysConstants.MACAU_IP); + String isMacauIP = String.valueOf(NetworkUtil.isMacauIp(accessIp,macauIpSetting.getKeyValues())); + LogUtil.info(MobileLoginController.class, "[preHandle] MockTest isMacauIP:" + isMacauIP); + response.setHeader("MacauIP", isMacauIP); + } + response.setHeader("IsInternal",String.valueOf(isInternal)); + int loginTag = authService.checkLoginByLoginIdAndPasswordAndIp(userId, password, accessIp); + if(loginTag>0) { + LoginUserInfo loginUser = new LoginUserInfo(); + loginUser.setId(0L); + loginUser.setLoginId(userId); + Token accessToken = JwtTokenUtil.generateTokenByLoginUser(request.getRequestURI(),loginUser, SysConstants.MOBILE_TOKEN_TYPE,false); + userTokenService.saveToken(accessToken); + Token refreshToken = JwtTokenUtil.generateTokenByLoginUser(request.getRequestURI(),loginUser, SysConstants.MOBILE_TOKEN_TYPE,true); + userTokenService.saveToken(refreshToken); + result.setSuccess(true); + result.setData(accessToken.getToken()); + result.setAccessToken(accessToken.getToken()); + result.setRefreshToken(refreshToken.getToken()); + } else if (loginTag == -4) { + result.setSuccess(false); + result.setCode("ERROR_IP_BANNED"); + } else if(loginTag == -2) { + result.setSuccess(false); + result.setCode("ERROR_LOCKED"); +// return ResponseEntity.status(HttpStatus.FORBIDDEN).body(result); + } else { + result.setSuccess(false); + } + LogUtil.info(MobileLoginController.class,"[checkLoginByLoginIdAndPasswordAndIp][Local account]userId="+ userId +",resultTag"+String.valueOf(loginTag)); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @RequestMapping(value = "/app/sso/user_sso_login", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity userSsoLogin(HttpServletRequest request, HttpServletResponse response, @RequestBody(required=true) SsoLoginRequest ssoLoginRequest) throws IOException { + SsoLoginResponse result = new SsoLoginResponse(); + LoginUserInfo loginUser= null; + String tokenData =""; + + if(StringUtils.isNotBlank(ssoLoginRequest.getSamlResponse())) { + tokenData = ssoLoginRequest.getSamlResponse(); + loginUser= ADFSUtil.parseADFSToken(tokenData); + loginUser.setGroupName(hasDBGroup(loginUser.getGroupName())); + }else if(StringUtils.isNotBlank(ssoLoginRequest.getIdToken())) { + tokenData = ssoLoginRequest.getIdToken(); + loginUser= ADFSUtil.parseJWTToken(tokenData); + } + if(StringUtils.isBlank(tokenData)) { + result.setSuccess(false); + result.setMessage("Token data is empty."); + result.setLogMessage("Token data is empty."); + }else { + if(loginUser==null) { + result.setSuccess(false); + result.setMessage("SSO Login Failed."); + }else if(loginUser.getLoginId()==null){ + result.setSuccess(false); + result.setMessage("Can not get login ID."); + }else { + String userId = loginUser.getLoginId().toLowerCase(); + if(userId.contains("@")) { + String[] userIdArr = StringUtils.split(userId,"@"); + userId = userIdArr[0]; + } + if(userId.contains("dev")) { + userId = userId.replace("dev", ""); + } + BaseApiResponse serviceResult = mgmUserService.findUserInfoByUserId(userId); + if(serviceResult.isSuccess()) { + UserInfoApiRecord userInfo = serviceResult.getData(); + userInfo.setLoginTag(true); + //--get group permissions + List userPermissions = sysGroupPermissionService.getRouterPermissionsByGroupName(loginUser.getGroupName()); + if(!userPermissions.isEmpty()) { + for(SysRouterPermission per:userPermissions) { + if(SysConstants.PERMISSION_APP_VIEW_BOOKING.equals(per.getId())) userInfo.setCanViewBooking(true); + if(SysConstants.PERMISSION_APP_NEW_BOOKING.equals(per.getId())) userInfo.setCanNewBooking(true); + if(SysConstants.PERMISSION_APP_TODO_LIST.equals(per.getId())) userInfo.setCanViewTodoList(true); + if(SysConstants.PERMISSION_APP_DASHBOARD.equals(per.getId())) userInfo.setCanViewDashboard(true); + if(SysConstants.PERMISSION_APP_APPROVAL.equals(per.getId())) userInfo.setCanViewApproval(true); + } + } + Token accessToken = JwtTokenUtil.generateTokenByLoginUser(request.getRequestURI(),loginUser, SysConstants.MOBILE_TOKEN_TYPE,false); + userTokenService.saveToken(accessToken); + Token refreshToken = JwtTokenUtil.generateTokenByLoginUser(request.getRequestURI(),loginUser, SysConstants.MOBILE_TOKEN_TYPE,true); + userTokenService.saveToken(refreshToken); + result.setSuccess(true); + result.setIdToken(tokenData); + result.setAccessToken(accessToken.getToken()); + result.setRefreshToken(refreshToken.getToken()); + result.setUserData(userInfo); + result.setClientId(EncryptUtil.sha256(Base64Util.encode("mcrm_" + userId))); + }else { + result.setSuccess(false); + result.setMessage(serviceResult.getMessage()); + } + } + } + String accessIp = NetworkUtil.getClientIpAddr(request); + boolean isInternal = NetworkUtil.isMatchInternal(accessIp); + String remoteAddr = request.getRemoteAddr(); + if(!isInternal){ + LogUtil.info(MobileLoginController.class, "[preHandle] getRealIp:" + accessIp); + CfgSettings macauIpSetting = settingService.getSettingByKey(SysConstants.MACAU_IP); + String isMacauIP = String.valueOf(NetworkUtil.isMacauIp(accessIp,macauIpSetting.getKeyValues())); + LogUtil.info(MobileLoginController.class, "[preHandle] MockTest isMacauIP:" + isMacauIP); + response.setHeader("MacauIP", isMacauIP); + } + response.setHeader("IsInternal",String.valueOf(isInternal)); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + // 接入SSO的时候修改此方法 + @RequestMapping(value = "/app/sso/get_sso_token_by_code", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity getTokenByCode(HttpServletRequest request, HttpServletResponse response, @RequestBody(required=true) SsoLoginRequest ssoLoginRequest) { + String code = ssoLoginRequest.getCode(); + boolean mockSSO = ssoLoginRequest.isMockSSO(); + String clientId = request.getHeader("ClientId"); + boolean res = JwtTokenUtil.checkToken(code, clientId); + Token dbToken = userTokenService.getToken(code); + if(dbToken==null) { + LogUtil.error(MobileLoginController.class, "[checkToken] No DB Token"); + res = false; + } + SsoLoginResponse result = new SsoLoginResponse(); + if(!res) { + result.setSuccess(false); + result.setMessage("Invalid Token"); + } + String ssoToken = ""; + String userId = ""; + if(mockSSO) { + ssoToken = code; + userId = JWT.decode(ssoToken).getClaim("login_id").asString(); + }else { + ssoToken = ""; // 调用SSO API + userId = ""; + } + BaseApiResponse serviceResult = mgmUserService.findUserInfoByUserId(userId); + if(serviceResult.isSuccess()) { + UserInfoApiRecord userInfo = serviceResult.getData(); + userInfo.setLoginTag(true); + LoginUserInfo user = new LoginUserInfo(); + CfgSections section = sectionDao.getByName(userInfo.getSection()); + userInfo.setSectionId(section.getId()); + user.setLoginId(userId); + user.setGroupName(userInfo.getGroupName()); + + userTokenService.clearTokenByUser(userId,SysConstants.MOBILE_TOKEN_TYPE); + Token accessToken = JwtTokenUtil.generateTokenByLoginUser(request.getRequestURI(),user, SysConstants.MOBILE_TOKEN_TYPE,false); + userTokenService.saveToken(accessToken); + Token refreshToken = JwtTokenUtil.generateTokenByLoginUser(request.getRequestURI(),user, SysConstants.MOBILE_TOKEN_TYPE,true); + userTokenService.saveToken(refreshToken); + + result.setIdToken(ssoToken); + result.setAccessToken(accessToken.getToken()); + result.setRefreshToken(refreshToken.getToken()); + result.setUserData(userInfo); + result.setClientId(EncryptUtil.sha256(Base64Util.encode("mcrm_"+userId))); + result.setSuccess(true); + }else { + result.setSuccess(false); + result.setMessage(serviceResult.getMessage()); + } + return ResponseEntity.status(HttpStatus.OK).body(result); + } + @RequestMapping(value = "/app/me", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public HashMap verifyToken(HttpServletRequest request, HttpServletResponse response) { + HashMap objReturn = new HashMap(); + // 这里可以return一些信息,每次刷新页面或者跳转页面的时候重新拿一次某些信息。 + objReturn.put("status", 200); + return objReturn; + } + @RequestMapping(value = "/app/refresh_token", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity refreshToken(HttpServletRequest request, HttpServletResponse response) throws IOException { + + String isReNew = request.getParameter("isRenewRefreshToken"); + + boolean isRenewRefreshToken = (!"false".equalsIgnoreCase(isReNew)); + RefreshTokenResponse result = new RefreshTokenResponse(); + LoginUserInfo loginUser = JwtTokenUtil.parseUserFromRequest(request); + if(loginUser!=null){ + Token accessToken = JwtTokenUtil.generateTokenByLoginUser(request.getRequestURI(),loginUser,SysConstants.MOBILE_TOKEN_TYPE,false); + userTokenService.updateTokenByUniqueId(loginUser.getTokenUuid(),SysConstants.MOBILE_TOKEN_TYPE,accessToken); + result.setAccessToken(accessToken.getToken()); + if(isRenewRefreshToken){ + Token refreshToken = JwtTokenUtil.generateTokenByLoginUser(request.getRequestURI(),loginUser,SysConstants.MOBILE_TOKEN_TYPE,true); + userTokenService.saveToken(refreshToken); + result.setRefreshToken(refreshToken.getToken()); + if(StringUtils.isNotBlank(loginUser.getTokenUuid())){ + userTokenService.removeTokenByUniqueId(loginUser.getTokenUuid(),SysConstants.MOBILE_TOKEN_TYPE); + } + } + result.setSuccess(true); + return ResponseEntity.status(HttpStatus.OK).body(result); + }else{ + result.setSuccess(false); + result.setCode("401"); + result.setMessage("Unauthorized operation"); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(result); + } + } + + @RequestMapping(value="/app/logout",method = RequestMethod.POST) + public BaseApiResponse logout(HttpServletRequest request) { + LoginUserInfo loginUser = JwtTokenUtil.parseUserFromRequest(request); + int count = 0; + if(loginUser!=null){ + count = userTokenService.clearTokenByUser(loginUser.getLoginId(),SysConstants.MOBILE_TOKEN_TYPE); + } + BaseApiResponse result = new BaseApiResponse<>(); + result.setSuccess(true); + result.setMessage("Logout successful"); + result.setData(count); + return result; + } + + @RequestMapping(value = "/web/user/lookup", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> lookupUser(HttpServletRequest request, HttpServletResponse response, + @RequestBody UserLookupRequest params) throws Exception { + BaseApiResponse result = new BaseApiResponse<>(); + String userId = params.getUserId(); + + if (StringUtils.isEmpty(userId)) { + response.sendError(422, "Miss parameter userId"); + return null; + } + + if(!StringUtils.isEmpty(userId)) { + userId = userId.replace("@mgm.mo", ""); + } + + BaseApiResponse serviceResult = mgmUserService.findUserInfoByUserId(userId); + if(serviceResult.isSuccess()) { + result.setSuccess(true); + result.setData(serviceResult.getData()); + }else { + result.setSuccess(false); + result.setMessage(serviceResult.getMessage()); + } + //-- + + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @RequestMapping(value = "/web/user/lookup_name", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity>> lookupUserName(HttpServletRequest request, HttpServletResponse response, + @RequestBody UserLookupRequest params) throws Exception { + String userName = params.getUserName(); + if (StringUtils.isEmpty(userName)) { + response.sendError(422, "Miss parameter userName"); + return null; + } + BaseApiResponse> result = mgmUserService.findUserInfoByUserName(userName); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @RequestMapping(value = "/web/user/check_approver", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> checkApprover(HttpServletRequest request, HttpServletResponse response, + @RequestBody CheckApproverResult params) throws Exception { + BaseApiResponse result = new BaseApiResponse<>(); + String userId = params.getUserId(); + String userName = params.getUserName(); + String roomType = params.getRoomType(); + String property = params.getProperty(); + + if(!StringUtils.isEmpty(userId)) { + userId = userId.replace("@mgm.mo", ""); + } + + if ((StringUtils.isEmpty(userId)&&StringUtils.isEmpty(userName))||StringUtils.isEmpty(roomType)||StringUtils.isEmpty(property)) { + result.setSuccess(false); + result.setMessage("Miss parameter"); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + BaseApiResponse checkResult = mgmUserService.checkApprover(userId,userName,roomType,property); + + if(SysCommon.mgmApiMockup) { + CheckApproverResult resultObj = new CheckApproverResult(); + resultObj.setIsApprover("1"); + resultObj.setProperty(property); + resultObj.setUserName("test"); + resultObj.setUserId("80001"); + resultObj.setRoomCategory(roomType); + resultObj.setStatusCode("OK"); + checkResult.setSuccess(true); + if("80001".equals(userId)||"test".equals(userName)) { + + }else { + resultObj.setUserId(null); + resultObj.setUserName(null); + resultObj.setIsApprover("0"); + } + checkResult.setData(resultObj); + } + + if(checkResult.isSuccess()) { + result.setSuccess(true); + result.setData(checkResult.getData()); + }else { + result.setSuccess(false); + result.setMessage(checkResult.getMessage()); + } + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + // ADFS登录时 判断返回的User Group是否存在DB中 + public String hasDBGroup(String group) { + if (group == null || group.trim().isEmpty()) { + return ""; + } + + String[] groups = group.split(";"); + StringBuilder dbGroupBuilder = new StringBuilder(); + + for (String groupName : groups) { + if (groupName == null || groupName.trim().isEmpty()) { + continue; + } + + SysGroup sysGroup = sysGroupDao.findByDisplayName(groupName.trim()); + if (sysGroup != null && sysGroup.getDisplayName() != null) { + if (!dbGroupBuilder.isEmpty()) { + dbGroupBuilder.append(";"); + } + dbGroupBuilder.append(sysGroup.getDisplayName()); + } + } + + return dbGroupBuilder.toString(); + } + +} diff --git a/src/main/java/com/mgm/mcrm/authorization/dtos/AccountLoginRequest.java b/src/main/java/com/mgm/mcrm/authorization/dtos/AccountLoginRequest.java new file mode 100644 index 0000000..39a8b04 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/dtos/AccountLoginRequest.java @@ -0,0 +1,13 @@ +package com.mgm.mcrm.authorization.dtos; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +@Data +public class AccountLoginRequest { + @NotBlank + private String userId; + @NotBlank + private String credential; + private String propertyCode; +} diff --git a/src/main/java/com/mgm/mcrm/authorization/dtos/AccountLoginResponse.java b/src/main/java/com/mgm/mcrm/authorization/dtos/AccountLoginResponse.java new file mode 100644 index 0000000..d555a0c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/dtos/AccountLoginResponse.java @@ -0,0 +1,12 @@ +package com.mgm.mcrm.authorization.dtos; + +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class AccountLoginResponse extends BaseApiResponse { + private String accessToken; + private String refreshToken; +} diff --git a/src/main/java/com/mgm/mcrm/authorization/dtos/LoginInfo.java b/src/main/java/com/mgm/mcrm/authorization/dtos/LoginInfo.java new file mode 100644 index 0000000..6eb9d30 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/dtos/LoginInfo.java @@ -0,0 +1,22 @@ +package com.mgm.mcrm.authorization.dtos; + +import java.sql.Date; +import java.util.List; + +import com.mgm.mcrm.authorization.models.SysRouter; +import com.mgm.mcrm.authorization.models.SysRouterPermission; +import com.mgm.mcrm.authorization.models.SysUserSetting; +import com.mgm.mcrm.authorization.models.SysUserView; +import lombok.Data; + +@Data +public class LoginInfo { + private SysUserView loginUser; + private String defaultRouter; + private String accessToken; + private Date lastPostTime; + private List listUserSetting; + private List listRouter; + private List listGroupPermission; + +} diff --git a/src/main/java/com/mgm/mcrm/authorization/dtos/LoginUserInfo.java b/src/main/java/com/mgm/mcrm/authorization/dtos/LoginUserInfo.java new file mode 100644 index 0000000..4ab8038 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/dtos/LoginUserInfo.java @@ -0,0 +1,12 @@ +package com.mgm.mcrm.authorization.dtos; + +import lombok.Data; + +@Data +public class LoginUserInfo { + private Long id; + private String loginId; + private String displayName; + private String groupName; + private String tokenUuid; +} diff --git a/src/main/java/com/mgm/mcrm/authorization/dtos/RefreshTokenResponse.java b/src/main/java/com/mgm/mcrm/authorization/dtos/RefreshTokenResponse.java new file mode 100644 index 0000000..305daba --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/dtos/RefreshTokenResponse.java @@ -0,0 +1,20 @@ +package com.mgm.mcrm.authorization.dtos; + + +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +@Schema(description = "Response info of refreshing App access token") +public class RefreshTokenResponse extends BaseApiResponse { + + @Schema(description = "New API JWT token generated") + private String accessToken; + + @Schema(description = "New Refresh JWT token generated") + private String refreshToken; + +} diff --git a/src/main/java/com/mgm/mcrm/authorization/dtos/SsoLoginRequest.java b/src/main/java/com/mgm/mcrm/authorization/dtos/SsoLoginRequest.java new file mode 100644 index 0000000..1bd5828 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/dtos/SsoLoginRequest.java @@ -0,0 +1,11 @@ +package com.mgm.mcrm.authorization.dtos; + +import lombok.Data; + +@Data +public class SsoLoginRequest { + private String samlResponse; + private String idToken; + private String code; + private boolean mockSSO=false; +} diff --git a/src/main/java/com/mgm/mcrm/authorization/dtos/SsoLoginResponse.java b/src/main/java/com/mgm/mcrm/authorization/dtos/SsoLoginResponse.java new file mode 100644 index 0000000..8e293af --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/dtos/SsoLoginResponse.java @@ -0,0 +1,16 @@ +package com.mgm.mcrm.authorization.dtos; + +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.common.dtos.mgm_api.UserInfoApiRecord; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +public class SsoLoginResponse extends BaseApiResponse { + private String idToken; + private String accessToken; + private String refreshToken; + private UserInfoApiRecord userData; + private String clientId; +} diff --git a/src/main/java/com/mgm/mcrm/authorization/dtos/UserLookupRequest.java b/src/main/java/com/mgm/mcrm/authorization/dtos/UserLookupRequest.java new file mode 100644 index 0000000..8ccd5c1 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/dtos/UserLookupRequest.java @@ -0,0 +1,9 @@ +package com.mgm.mcrm.authorization.dtos; + +import lombok.Data; + +@Data +public class UserLookupRequest { + private String userName; + private String userId; +} diff --git a/src/main/java/com/mgm/mcrm/authorization/filters/JwtAuthFilter.java b/src/main/java/com/mgm/mcrm/authorization/filters/JwtAuthFilter.java new file mode 100644 index 0000000..1ef8e41 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/filters/JwtAuthFilter.java @@ -0,0 +1,183 @@ +package com.mgm.mcrm.authorization.filters; + +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.exceptions.JWTVerificationException; +import com.auth0.jwt.exceptions.SignatureVerificationException; +import com.auth0.jwt.exceptions.TokenExpiredException; +import com.mgm.mcrm.appsetting.models.CfgSettings; +import com.mgm.mcrm.appsetting.services.SettingService; +import com.mgm.mcrm.authorization.dtos.LoginUserInfo; +import com.mgm.mcrm.authorization.models.Token; +import com.mgm.mcrm.authorization.services.UserTokenService; +import com.mgm.mcrm.authorization.utils.JwtTokenUtil; +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.constants.SysConstants; +import com.mgm.mcrm.common.utils.EncryptUtil; +import com.mgm.mcrm.common.utils.LogUtil; +import com.mgm.mcrm.common.utils.NetworkUtil; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.NonNull; +import lombok.Setter; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.util.Base64Util; +import org.springframework.util.AntPathMatcher; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +public class JwtAuthFilter extends OncePerRequestFilter { + + private final AntPathMatcher pathMatcher = new AntPathMatcher(); + @Setter + private List excludePatterns; + @Setter + private UserTokenService userTokenService; + @Setter + private SettingService settingService; + + private final List ignoreCheckInternalUrl = Arrays.asList( + "app/logout", + "app/me", + "save_confirm_log", + "refresh_token", + "write_log", + "get_list", + "mock_user_sso_login", + "sso/", + "get_setting_by_key" + ); + + @Override + protected void doFilterInternal( + @NonNull HttpServletRequest request, + @NonNull HttpServletResponse response, + @NonNull FilterChain filterChain + ) throws ServletException, IOException{ + boolean validatePass = true; + try { + String token = request.getHeader("Authorization"); + if(StringUtils.isNotBlank(token) && token.startsWith("Bearer ")){ + token = token.substring(7); + } + Token dbToken = userTokenService.getToken(token); + if(StringUtils.isNotBlank(token) && dbToken!=null) { + JWTVerifier jwtVerifier = JwtTokenUtil.getJwtVerifier(); + try { + jwtVerifier.verify(token); + } + catch (SignatureVerificationException e) { + LogUtil.error(JwtAuthFilter.class, "[preHandle] SignatureVerificationException \nException Message:" + e.getMessage()); + sendErrorResponse(response,400, e.getMessage()); + validatePass=false; + } + catch (TokenExpiredException e) { + if(!request.getRequestURI().contains("refresh_token")) { + LogUtil.error(JwtAuthFilter.class, "[preHandle] TokenExpiredException \nException Message:" + e.getMessage()); + sendErrorResponse(response,401, e.getMessage()); + validatePass=false; + } + } + catch (JWTVerificationException e) { + LogUtil.error(JwtAuthFilter.class, "[preHandle] JWTVerificationException \nException Message:" + e.getMessage()); + sendErrorResponse(response,403, e.getMessage()); + validatePass=false; + } + catch (Exception e) { + LogUtil.error(JwtAuthFilter.class, "[preHandle] Exception \nException Message:" + e.getMessage()); + sendErrorResponse(response,500, e.getMessage()); + validatePass=false; + } + String clientId = request.getHeader("clientId"); + if(clientId==null) { + clientId=""; + } + LoginUserInfo user = JwtTokenUtil.parseUserFromToken(token); + if(user!=null) { + String encrypt = EncryptUtil.sha256(Base64Util.encode("mcrm_"+user.getLoginId())); + if(!clientId.equalsIgnoreCase(encrypt)) { + sendErrorResponse(response,500, "Invalid Token"); + validatePass=false; + } + }else { + LogUtil.info(JwtAuthFilter.class, "[preHandle] user null"); + sendErrorResponse(response,500, "Invalid Token"); + validatePass=false; + } + }else if(!"OPTIONS".equalsIgnoreCase(request.getMethod())) { + LogUtil.error(JwtAuthFilter.class, "[preHandle] Exception Method: " + request.getMethod()); + sendErrorResponse(response,401, "Invalid Token"); + validatePass=false; + } + }catch(Exception ex) { + LogUtil.error(JwtAuthFilter.class, "[preHandle] Exception \nException Message:" + ex.getMessage()); + sendErrorResponse(response,500, ex.getMessage()); + validatePass=false; + } + if(!"OPTIONS".equalsIgnoreCase(request.getMethod()) && validatePass){ + boolean allowIP = NetworkUtil.isRequestFromTrustedSource(request); + if(!allowIP) { + sendErrorResponse(response,401, "Invalid Internal IP"); + validatePass=false; + }else{ + boolean canAccessIP = true; + String accessIp = NetworkUtil.getClientIpAddr(request); + if("INVALID_IP".equalsIgnoreCase(accessIp)){ + sendErrorResponse(response,401, "Invalid IP in forward headers"); + validatePass = false; + } + boolean isInternal = NetworkUtil.isMatchInternal(accessIp); + if(!isInternal) { + String uri = request.getRequestURI(); + boolean isIgnoreUrl = false; + for(String urlKey:ignoreCheckInternalUrl){ + if(uri.contains(urlKey)){ + isIgnoreUrl=true; + break; + } + } + if(!isIgnoreUrl){ + LogUtil.info(JwtAuthFilter.class, "[preHandle] getRealIp:" + accessIp); + CfgSettings macauIpSetting = settingService.getSettingByKey(SysConstants.MACAU_IP); + String isMacauIP = String.valueOf(NetworkUtil.isMacauIp(accessIp,macauIpSetting.getKeyValues())); + LogUtil.info(JwtAuthFilter.class, "[preHandle] isMacauIP:" + isMacauIP); + response.setHeader("MacauIP", isMacauIP); + if("false".equals(isMacauIP)) + canAccessIP = false; + LogUtil.info(JwtAuthFilter.class, "[preHandle] canAccessIP:" + canAccessIP); + } + }else { + response.setHeader("MacauIP", ""); + } + response.setHeader("IsInternal",String.valueOf(isInternal)); + if(!canAccessIP) { + validatePass=false; + } + } + } + if(validatePass){ + filterChain.doFilter(request, response); + } + } + + + @Override + protected boolean shouldNotFilter(@NonNull HttpServletRequest request) { + if (excludePatterns == null) { + return false; + } + return excludePatterns.stream() + .anyMatch(pattern -> pathMatcher.match(pattern, request.getRequestURI())); + } + + private void sendErrorResponse(HttpServletResponse response, int errorCode, String errorMessage) throws IOException { + response.setStatus(errorCode); + response.setContentType("application/text"); + response.setCharacterEncoding("UTF-8"); + response.getWriter().write(errorMessage); + } +} diff --git a/src/main/java/com/mgm/mcrm/authorization/models/SysGroup.java b/src/main/java/com/mgm/mcrm/authorization/models/SysGroup.java new file mode 100644 index 0000000..5badafc --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/models/SysGroup.java @@ -0,0 +1,43 @@ +package com.mgm.mcrm.authorization.models; + +import java.io.Serializable; +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 lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@Entity +@Table(name="sys_groups") +public class SysGroup implements Serializable { + //fields in table + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="display_name") + private String displayName; + @Column(name="default_property") + private String defaultProperty; + @Column(name="status") + private Integer status; + @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; + +} diff --git a/src/main/java/com/mgm/mcrm/authorization/models/SysGroupDataPermission.java b/src/main/java/com/mgm/mcrm/authorization/models/SysGroupDataPermission.java new file mode 100644 index 0000000..90a1db5 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/models/SysGroupDataPermission.java @@ -0,0 +1,34 @@ +package com.mgm.mcrm.authorization.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 lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@Entity +@Table(name="sys_group_data_permissions") +public class SysGroupDataPermission { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name = "group_id") + private Long groupId; + @Column(name="data_id") + private String dataId; + @Column(name="data_type") + private String dataType; + @Column(name="permission_id") + private String permissionId; + +} diff --git a/src/main/java/com/mgm/mcrm/authorization/models/SysGroupPermission.java b/src/main/java/com/mgm/mcrm/authorization/models/SysGroupPermission.java new file mode 100644 index 0000000..7875e2f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/models/SysGroupPermission.java @@ -0,0 +1,28 @@ +package com.mgm.mcrm.authorization.models; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.Table; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@Entity +@Table(name="sys_group_permissions") +@IdClass(SysGroupPermissionKey.class) +public class SysGroupPermission { + //fields in table + @Id + @Column(name = "group_id") + private Long groupId; + @Id + @Column(name="permission_id") + private String permissionId; + +} diff --git a/src/main/java/com/mgm/mcrm/authorization/models/SysGroupPermissionKey.java b/src/main/java/com/mgm/mcrm/authorization/models/SysGroupPermissionKey.java new file mode 100644 index 0000000..872ea12 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/models/SysGroupPermissionKey.java @@ -0,0 +1,38 @@ +package com.mgm.mcrm.authorization.models; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Objects; + +@Getter +@Setter +@NoArgsConstructor +public class SysGroupPermissionKey implements Serializable{ + + @Serial + private static final long serialVersionUID = 6060166117433738173L; + private Long groupId ; + private String permissionId; + @Override + public boolean equals(Object o) { + if(o instanceof SysGroupPermissionKey) + { + SysGroupPermissionKey key = (SysGroupPermissionKey)o ; + if(Objects.equals(this.groupId, key.getGroupId()) && Objects.equals(this.permissionId, key.getPermissionId())) + { + return true ; + } + } + return false ; + } + + @Override + public int hashCode() { + return 1; + } + +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/authorization/models/SysRouter.java b/src/main/java/com/mgm/mcrm/authorization/models/SysRouter.java new file mode 100644 index 0000000..2daa30b --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/models/SysRouter.java @@ -0,0 +1,73 @@ +package com.mgm.mcrm.authorization.models; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +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.Transient; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.annotations.GenericGenerator; +import org.hibernate.annotations.Parameter; + +import com.fasterxml.jackson.annotation.JsonInclude; + +@Getter +@Setter +@NoArgsConstructor +@Entity +@Table(name="sys_routers") +public class SysRouter { + //fields in table + @Id + @JsonInclude(JsonInclude.Include.NON_NULL) + @Column(name = "id") + private String id; + @JsonInclude(JsonInclude.Include.NON_NULL) + @Column(name="parent_id") + private String parentId; + @JsonInclude(JsonInclude.Include.NON_NULL) + @Column(name="heading") + private String heading; + @JsonInclude(JsonInclude.Include.NON_NULL) + @Column(name="section_title") + private String sectionTitle; + @Column(name="route") + private String route; + @JsonInclude(JsonInclude.Include.NON_NULL) + @Column(name="svg_icon") + private String svgIcon; + @JsonInclude(JsonInclude.Include.NON_NULL) + @Column(name="font_icon") + private String fontIcon; + @JsonInclude(JsonInclude.Include.NON_NULL) + @Column(name="sort_no") + private Integer sortNo; + @JsonInclude(JsonInclude.Include.NON_NULL) + @Column(name="status") + private Integer status; + @JsonInclude(JsonInclude.Include.NON_NULL) + @Column(name="created_at") + private Date createdAt; + @JsonInclude(JsonInclude.Include.NON_NULL) + @Column(name="created_by") + private String createdBy; + @JsonInclude(JsonInclude.Include.NON_NULL) + @Column(name="updated_at") + private Date updatedAt; + @JsonInclude(JsonInclude.Include.NON_NULL) + @Column(name="updated_by") + private String updatedBy; + @Transient + @JsonInclude(JsonInclude.Include.NON_NULL) + private List sub; + +} diff --git a/src/main/java/com/mgm/mcrm/authorization/models/SysRouterPermission.java b/src/main/java/com/mgm/mcrm/authorization/models/SysRouterPermission.java new file mode 100644 index 0000000..6585a11 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/models/SysRouterPermission.java @@ -0,0 +1,31 @@ +package com.mgm.mcrm.authorization.models; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.persistence.Transient; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@Entity +@Table(name = "sys_router_permissions") +public class SysRouterPermission { + @Id + @Column(name = "id") + private String id; + @Column(name = "router_id") + private String routerId; + @Column(name = "permission_code") + private String permissionCode; + @Column(name = "permission_name") + private String permissionName; + @Transient + private boolean selected=false; + @Transient + private String dataPermissionTag; +} diff --git a/src/main/java/com/mgm/mcrm/authorization/models/SysUser.java b/src/main/java/com/mgm/mcrm/authorization/models/SysUser.java new file mode 100644 index 0000000..e79b67f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/models/SysUser.java @@ -0,0 +1,50 @@ +package com.mgm.mcrm.authorization.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.Transient; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@Entity +@Table(name="sys_users") +public class SysUser { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="login_id") + private String loginId; + @Column(name="display_name") + private String displayName; + @Column(name="password") + private String password; + @Column(name="category") + private Integer category; + @Column(name="status") + private Integer status; + @Column(name="try_times") + private Integer tryTimes; + @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; + @Transient + private String token; + +} diff --git a/src/main/java/com/mgm/mcrm/authorization/models/SysUserSetting.java b/src/main/java/com/mgm/mcrm/authorization/models/SysUserSetting.java new file mode 100644 index 0000000..9b99690 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/models/SysUserSetting.java @@ -0,0 +1,37 @@ +package com.mgm.mcrm.authorization.models; + +import java.io.Serializable; +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.IdClass; +import jakarta.persistence.Table; +import jakarta.persistence.Transient; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.annotations.GenericGenerator; +import org.hibernate.annotations.Parameter; + +@Getter +@Setter +@NoArgsConstructor +@Entity +@Table(name="sys_user_settings") +@IdClass(SysUserSettingKey.class) +public class SysUserSetting { + @Id + @Column(name="user_id") + private Long userId; + @Id + @Column(name="setting_key") + private String settingKey; + @Column(name="setting_value") + private String settingValue; + +} diff --git a/src/main/java/com/mgm/mcrm/authorization/models/SysUserSettingKey.java b/src/main/java/com/mgm/mcrm/authorization/models/SysUserSettingKey.java new file mode 100644 index 0000000..d0506ed --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/models/SysUserSettingKey.java @@ -0,0 +1,40 @@ +package com.mgm.mcrm.authorization.models; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Objects; + +@Getter +@Setter +@NoArgsConstructor +public class SysUserSettingKey implements Serializable{ + + @Serial + private static final long serialVersionUID = 6060166117433738173L; + private Long userId ; + private String settingKey; + + + @Override + public boolean equals(Object o) { + if(o instanceof SysUserSettingKey) + { + SysUserSettingKey key = (SysUserSettingKey)o ; + if(Objects.equals(this.userId, key.getUserId()) && Objects.equals(this.settingKey, key.getSettingKey())) + { + return true ; + } + } + return false ; + } + + @Override + public int hashCode() { + return 1; + } + +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/authorization/models/SysUserView.java b/src/main/java/com/mgm/mcrm/authorization/models/SysUserView.java new file mode 100644 index 0000000..6f405bb --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/models/SysUserView.java @@ -0,0 +1,57 @@ +package com.mgm.mcrm.authorization.models; + +import java.io.Serializable; +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.Transient; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@Entity +@Table(name="view_sys_user_group") +public class SysUserView implements Serializable{ + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="login_id") + private String loginId; + @Column(name="display_name") + private String displayName; + @Column(name="password") + private String password; + @Column(name="category") + private Integer category; + @Column(name="status") + private Integer status; + @Column(name="try_times") + private Integer tryTimes; + @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="group_id") + private Long groupId; + @Column(name="group_name") + private String groupName; + @Column(name="default_property") + private String defaultProperty; + @Transient + private String token; + +} diff --git a/src/main/java/com/mgm/mcrm/authorization/models/Token.java b/src/main/java/com/mgm/mcrm/authorization/models/Token.java new file mode 100644 index 0000000..a4a1a65 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/models/Token.java @@ -0,0 +1,37 @@ +package com.mgm.mcrm.authorization.models; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDateTime; + +@Getter +@Setter +@NoArgsConstructor +@Entity +@Table(name="token") +public class Token { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="token") + private String token; + @Column(name="created_at") + private LocalDateTime createdAt; + @Column(name="created_by") + private String createdBy; + @Column(name="updated_at") + private LocalDateTime updatedAt; + @Column(name="updated_by") + private String updatedBy; + @Column(name = "token_type") + private Integer tokenType; + @Column(name = "uuid") + private String uuid; + @Column(name = "expire_time") + private LocalDateTime expireTime; + +} diff --git a/src/main/java/com/mgm/mcrm/authorization/repositories/SysGroupDao.java b/src/main/java/com/mgm/mcrm/authorization/repositories/SysGroupDao.java new file mode 100644 index 0000000..878fe74 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/repositories/SysGroupDao.java @@ -0,0 +1,23 @@ +package com.mgm.mcrm.authorization.repositories; + +import java.util.List; + +import com.mgm.mcrm.authorization.models.SysGroup; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + + + +public interface SysGroupDao extends JpaRepository { + SysGroup findByDisplayName(String displayName); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + +} diff --git a/src/main/java/com/mgm/mcrm/authorization/repositories/SysGroupDataPermissionDao.java b/src/main/java/com/mgm/mcrm/authorization/repositories/SysGroupDataPermissionDao.java new file mode 100644 index 0000000..1051e3e --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/repositories/SysGroupDataPermissionDao.java @@ -0,0 +1,22 @@ +package com.mgm.mcrm.authorization.repositories; + +import java.util.List; + +import com.mgm.mcrm.authorization.models.SysGroupDataPermission; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + + + +public interface SysGroupDataPermissionDao extends JpaRepository { + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + + @Query(value = "select data_id from sys_group_data_permissions d" + + " where group_id in (select id from sys_groups where upper(display_name) in (?1)) " + + " and permission_id=?2 and data_type=?3 ",nativeQuery=true) + List queryAccessDataByGroupNameAndType(List groupNameList, String routerId, String dataType); + +} diff --git a/src/main/java/com/mgm/mcrm/authorization/repositories/SysGroupPermissionDao.java b/src/main/java/com/mgm/mcrm/authorization/repositories/SysGroupPermissionDao.java new file mode 100644 index 0000000..d7c417a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/repositories/SysGroupPermissionDao.java @@ -0,0 +1,20 @@ +package com.mgm.mcrm.authorization.repositories; + +import java.util.List; + +import com.mgm.mcrm.authorization.models.SysGroupPermission; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + + + +public interface SysGroupPermissionDao extends JpaRepository { + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + + @Query(value="select * from sys_group_permissions where group_id=?1",nativeQuery=true) + List getAllByGroupId(long groupId); + +} diff --git a/src/main/java/com/mgm/mcrm/authorization/repositories/SysRouterDao.java b/src/main/java/com/mgm/mcrm/authorization/repositories/SysRouterDao.java new file mode 100644 index 0000000..0481e6b --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/repositories/SysRouterDao.java @@ -0,0 +1,22 @@ +package com.mgm.mcrm.authorization.repositories; + +import java.util.List; + +import com.mgm.mcrm.authorization.models.SysRouter; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + + + +public interface SysRouterDao extends JpaRepository { + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + +} diff --git a/src/main/java/com/mgm/mcrm/authorization/repositories/SysRouterPermissionDao.java b/src/main/java/com/mgm/mcrm/authorization/repositories/SysRouterPermissionDao.java new file mode 100644 index 0000000..c9cf699 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/repositories/SysRouterPermissionDao.java @@ -0,0 +1,31 @@ +package com.mgm.mcrm.authorization.repositories; + +import java.util.List; + +import com.mgm.mcrm.authorization.models.SysRouter; +import com.mgm.mcrm.authorization.models.SysRouterPermission; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +public interface SysRouterPermissionDao extends JpaRepository { + + List findAll(Specification spec, Sort sort); + + List findAll(Specification spec); + + Page findAll(Specification spec, Pageable pageable); + + @Query(""" + select rp + from SysRouterPermission rp + join SysGroupPermission grp on rp.id = grp.permissionId + join SysGroup g on g.id = grp.groupId + where g.displayName in (?1) + """) + List queryPermssionByGroupNameList(List groupNameList); + +} diff --git a/src/main/java/com/mgm/mcrm/authorization/repositories/SysUserDao.java b/src/main/java/com/mgm/mcrm/authorization/repositories/SysUserDao.java new file mode 100644 index 0000000..75e4087 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/repositories/SysUserDao.java @@ -0,0 +1,33 @@ +package com.mgm.mcrm.authorization.repositories; + +import java.util.List; + +import com.mgm.mcrm.authorization.models.SysUser; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + + + +public interface SysUserDao extends JpaRepository { + SysUser findById(long id); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + + @Transactional + @Modifying + @Query(value = " delete from sys_users where ID=?1 ",nativeQuery=true) + int deleteById(long id); + + @Query(value="select * from sys_users where upper(login_id) =?1",nativeQuery=true) + SysUser getByLoginId(String loginId); + + @Query(value = "select count(1) as user_cnt from sys_users where upper(login_id) =?1 and password=?2 ",nativeQuery=true) + int countSysUserByLoginIdAndPassword(String loginId, String password); +} diff --git a/src/main/java/com/mgm/mcrm/authorization/repositories/SysUserSettingDao.java b/src/main/java/com/mgm/mcrm/authorization/repositories/SysUserSettingDao.java new file mode 100644 index 0000000..c49b712 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/repositories/SysUserSettingDao.java @@ -0,0 +1,13 @@ +package com.mgm.mcrm.authorization.repositories; + +import java.util.List; + +import com.mgm.mcrm.authorization.models.SysUserSetting; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + + + +public interface SysUserSettingDao extends JpaRepository { + +} diff --git a/src/main/java/com/mgm/mcrm/authorization/repositories/SysUserViewDao.java b/src/main/java/com/mgm/mcrm/authorization/repositories/SysUserViewDao.java new file mode 100644 index 0000000..4519af6 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/repositories/SysUserViewDao.java @@ -0,0 +1,25 @@ +package com.mgm.mcrm.authorization.repositories; + +import java.util.List; + +import com.mgm.mcrm.authorization.models.SysUserView; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + + + +public interface SysUserViewDao extends JpaRepository { + SysUserView findById(long id); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + + + @Query(value="select * from view_sys_user_group where upper(login_id) =?1",nativeQuery=true) + SysUserView getByLoginId(String loginId); + +} diff --git a/src/main/java/com/mgm/mcrm/authorization/repositories/TokenDao.java b/src/main/java/com/mgm/mcrm/authorization/repositories/TokenDao.java new file mode 100644 index 0000000..076f8cf --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/repositories/TokenDao.java @@ -0,0 +1,37 @@ +package com.mgm.mcrm.authorization.repositories; + +import com.mgm.mcrm.authorization.models.Token; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + + + + +public interface TokenDao extends JpaRepository { + Token findById(long id); + + @Deprecated + Token findByToken(String token); + + Token findByUuid(String uuid); + + Token findByUuidAndTokenType(String uuid, int tokenType); + + @Deprecated + @Transactional + @Modifying + @Query(value = " delete from token where token=?1 ",nativeQuery=true) + int deleteByToken(String token); + + @Transactional + @Modifying + @Query(value = " delete from token where uuid=?1 and token_type=?2 ",nativeQuery=true) + int deleteByUuidAndTokenType(String uuid, int tokenType); + + @Transactional + @Modifying + @Query(value = " delete from token where created_by=?1 and token_type=?2 ",nativeQuery=true) + int deleteByUserIdAndTokenType(String userId, int tokenType); +} diff --git a/src/main/java/com/mgm/mcrm/authorization/services/AuthorizationService.java b/src/main/java/com/mgm/mcrm/authorization/services/AuthorizationService.java new file mode 100644 index 0000000..d9b940e --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/services/AuthorizationService.java @@ -0,0 +1,165 @@ +package com.mgm.mcrm.authorization.services; + +import java.util.*; + +import com.google.gson.Gson; +import com.mgm.mcrm.authorization.models.SysRouterPermission; +import com.mgm.mcrm.authorization.models.SysUser; +import com.mgm.mcrm.authorization.repositories.SysGroupDataPermissionDao; +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.logging.services.SysLogLoginIpService; +import jakarta.annotation.Resource; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import com.mgm.mcrm.logging.models.SysLogLoginIp; +import com.mgm.mcrm.appsetting.models.CfgSettings; +import com.mgm.mcrm.appsetting.services.SettingService; +import com.mgm.mcrm.common.utils.LogUtil; +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.authorization.repositories.SysUserDao; + +@Service +public class AuthorizationService { + + @Resource + private SysUserDao sysUserDao; + @Resource + private SysGroupDataPermissionDao sysGroupDataDao; + @Resource + private SysGroupPermissionDao sysGroupPermissionDao; + @Resource + private SysRouterPermissionDao routerPermissionDao; + + @Resource + private SettingService settingService; + @Resource + private SysLogLoginIpService sysLogLoginIpService; + + + // -4=ip has been banned, -3=disabled, -2=locked, -1 or 0=incorrect loginId or password, 1=success + public int checkLoginByLoginIdAndPasswordAndIp(String loginId, String password, String clientIp) { + + // IP 层级预检查 (已封禁直接拦截) + if (sysLogLoginIpService.isBanned(clientIp)) { + return -4; + } + + // 获取基础配置 + int maxIpTries = Integer.parseInt(settingService.getSettingByKey("TRY_USERNAME_TIMES").getKeyValues()); + int banMins = Integer.parseInt(settingService.getSettingByKey("RETRY_USERNAME_AFTER_MINS").getKeyValues()); + int maxPwdTries = Integer.parseInt(settingService.getSettingByKey("TRY_PASSWORD_TIMES").getKeyValues()); + + SysLogLoginIp sysLogLoginIp = sysLogLoginIpService.findTodayRecordByIp(clientIp); + if (sysLogLoginIp == null) { + sysLogLoginIp = new SysLogLoginIp(); + sysLogLoginIp.setIp(clientIp); + sysLogLoginIp.setTryTimes(0); + sysLogLoginIp.setLastLoginTimes(new Date()); + } + + // 用户是否存在校验 + SysUser loginUser = sysUserDao.getByLoginId(loginId); + if (loginUser == null) { + // 用户不存在,记录 IP 尝试次数 + return handleIpFailure(sysLogLoginIp, maxIpTries, banMins); + } + + // 用户状态检查 + if (loginUser.getStatus() == 2) return -2; // Locked + if (loginUser.getStatus() == 0) return -3; // Disabled + + if (SysCommon.appDebugLog) + LogUtil.info(AuthorizationService.class, + "[checkLoginByLoginIdAndPassword][Local account] Begin check local user, loginId=" + loginId); + + // 执行密码校验 + int checkPassed = sysUserDao.countSysUserByLoginIdAndPassword(loginId.toUpperCase(), password); + + if (checkPassed == 1) { + // 登录成功:重置计数 + loginUser.setTryTimes(0); + sysUserDao.save(loginUser); + + sysLogLoginIp.setTryTimes(0); + sysLogLoginIp.setLastLoginTimes(new Date()); + sysLogLoginIpService.save(sysLogLoginIp); + + if (SysCommon.appDebugLog) + LogUtil.info(AuthorizationService.class, + "[checkLoginByLoginIdAndPassword][Local account] End check local user, result=" + checkPassed); + + return 1; + } else { + // 登录失败:更新计数 + int currentIpTries = (sysLogLoginIp.getTryTimes() == null ? 0 : sysLogLoginIp.getTryTimes()) + 1; + int currentUserTries = (loginUser.getTryTimes() == null ? 0 : loginUser.getTryTimes()) + 1; + + sysLogLoginIp.setTryTimes(currentIpTries); + sysLogLoginIp.setLastLoginTimes(new Date()); + loginUser.setTryTimes(currentUserTries); + + int finalResult = -1; // 默认返回密码错误 + + // 检查是否触发 IP 封禁 + if (currentIpTries >= maxIpTries) { + applyBan(sysLogLoginIp, banMins); + finalResult = -4; + } + + // 检查是否触发 用户 锁定 + if (currentUserTries >= maxPwdTries) { + loginUser.setStatus(2); + loginUser.setTryTimes(0); + finalResult = -2; + } + + + String failMessge = ""; + if (finalResult == -1) { + failMessge = "incorrect password, "; + } else if (finalResult == -4) { + failMessge = "ip has been banned, "; + } else if (finalResult == -2) { + failMessge = "user has been banned, "; + } + + sysLogLoginIpService.save(sysLogLoginIp); + sysUserDao.save(loginUser); + + LogUtil.warn(AuthorizationService.class, + "[checkLoginByLoginIdAndPassword][Local account] End check local user, " + failMessge + "loginId=" + loginId + ", result=" + finalResult); + return finalResult; + } + } + + /** + * 封装的私有方法:处理 IP 失败逻辑 + */ + private int handleIpFailure(SysLogLoginIp ipLog, int maxTries, int banMins) { + int tries = (ipLog.getTryTimes() == null ? 0 : ipLog.getTryTimes()) + 1; + ipLog.setTryTimes(tries); + ipLog.setLastLoginTimes(new Date()); + + if (tries >= maxTries) { + applyBan(ipLog, banMins); + sysLogLoginIpService.save(ipLog); + return -4; + } + sysLogLoginIpService.save(ipLog); + return -1; + } + + /** + * 封装的私有方法:执行封禁 + */ + private void applyBan(SysLogLoginIp ipLog, int banMins) { + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.MINUTE, banMins); + ipLog.setBanUntil(cal.getTime()); + ipLog.setTryTimes(0); // 重置以便解封后计数 + } +} diff --git a/src/main/java/com/mgm/mcrm/authorization/services/MgmUserService.java b/src/main/java/com/mgm/mcrm/authorization/services/MgmUserService.java new file mode 100644 index 0000000..6550b93 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/services/MgmUserService.java @@ -0,0 +1,246 @@ +package com.mgm.mcrm.authorization.services; + +import java.util.ArrayList; +import java.util.List; + +import com.mgm.mcrm.authorization.models.SysGroupPermission; +import com.mgm.mcrm.authorization.models.SysUserView; +import com.mgm.mcrm.common.constants.SysConstants; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.common.services.MGMApiService; +import jakarta.annotation.Resource; + +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson.parser.Feature; +import com.alibaba.fastjson.JSONObject; + +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.basesetting.property.repositories.BlockDao; +import com.mgm.mcrm.basesetting.team.repositories.DepartmentDao; +import com.mgm.mcrm.basesetting.team.repositories.DivisionDao; +import com.mgm.mcrm.basesetting.property.repositories.PropertyDao; +import com.mgm.mcrm.basesetting.team.repositories.SectionDao; +import com.mgm.mcrm.basesetting.team.repositories.TeamStructureDao; +import com.mgm.mcrm.authorization.repositories.SysGroupPermissionDao; +import com.mgm.mcrm.authorization.repositories.SysUserViewDao; +import com.mgm.mcrm.basesetting.property.models.CfgBlocks; +import com.mgm.mcrm.basesetting.team.models.CfgDepartments; +import com.mgm.mcrm.basesetting.team.models.CfgDivisions; +import com.mgm.mcrm.basesetting.property.models.CfgProperties; +import com.mgm.mcrm.basesetting.team.models.CfgSections; +import com.mgm.mcrm.basesetting.team.models.CfgTeamStructure; +import com.mgm.mcrm.common.dtos.mgm_api.CheckApproverResult; +import com.mgm.mcrm.common.dtos.mgm_api.UserInfoApiRecord; +import com.mgm.mcrm.common.dtos.mgm_api.UserInfoApiResult; +import com.mgm.mcrm.common.dtos.http_util.HttpResponseResult; + +@Service +public class MgmUserService { + + @Resource + private MGMApiService mgmApiService; + @Resource + private PropertyDao propertyDao; + @Resource + private BlockDao blockDao; + @Resource + private DivisionDao divisionDao; + @Resource + private DepartmentDao departmentDao; + @Resource + private SectionDao sectionDao; + @Resource + private TeamStructureDao teamStructureDao; + @Resource + private SysUserViewDao sysUserViewDao; + @Resource + private SysGroupPermissionDao sysGroupPermissionDao; + + public BaseApiResponse findUserInfoByUserId(String userId) { + BaseApiResponse result = new BaseApiResponse<>(); + try { + HttpResponseResult httpResult = mgmApiService.invokeGetUserInfo(userId,""); + if(httpResult.getStatusCode()==200) { + try { + UserInfoApiResult resultObj = JSONObject.parseObject(httpResult.getResponseContent(),UserInfoApiResult.class,Feature.SupportNonPublicField,Feature.IgnoreNotMatch); + if(resultObj!=null && resultObj.getStatusCode()!=null) { + String resultCode = resultObj.getStatusCode(); + if("OK".equals(resultCode)) { + List recrods = resultObj.getRecords(); + if(!recrods.isEmpty()) { + UserInfoApiRecord user = recrods.getFirst(); + if(!"NULL".equals(user.getUserId())) { + this.supplementInfoId(userId,user); + user.setStatusCode(resultObj.getStatusCode()); + user.setStatusDescription(resultObj.getStatusDescription()); + result.setSuccess(true); + result.setData(user); + }else { + result.setSuccess(false); + result.setMessage("User not found"); + } + }else { + result.setSuccess(false); + result.setMessage("User not found"); + } + + }else { + result.setSuccess(false); + result.setMessage("UserInfo API return error:["+resultCode+"] "+resultObj.getStatusDescription()); + } + }else { + result.setSuccess(false); + result.setMessage("Invalid return data"); + } + }catch(Exception err) { + result.setSuccess(false); + result.setMessage("Parse return data failed:"+err.getMessage()); + } + + }else { + result.setSuccess(false); + result.setMessage("Invoke get user info failed:["+httpResult.getStatusCode()+"] "+httpResult.getErrorMessage()); + } + }catch(Exception err) { + result.setSuccess(false); + result.setMessage("Invoke get user info API error:"+err.getMessage()); + } + + return result; + } + + public BaseApiResponse> findUserInfoByUserName(String userName) { + BaseApiResponse> result = new BaseApiResponse<>(); + String userId = SysCommon.mgmApiMockup?"80001":""; + try { + HttpResponseResult httpResult = mgmApiService.invokeGetUserInfo(userId,userName); + if(httpResult.getStatusCode()==200) { + try { + UserInfoApiResult resultObj = JSONObject.parseObject(httpResult.getResponseContent(),UserInfoApiResult.class,Feature.SupportNonPublicField,Feature.IgnoreNotMatch); + if(resultObj!=null && resultObj.getStatusCode()!=null) { + String resultCode = resultObj.getStatusCode(); + if("OK".equals(resultCode)) { + List records = resultObj.getRecords(); + List getRecords = new ArrayList(); + for(UserInfoApiRecord rec : records) { + if(!"NULL".equals(rec.getUserId())) { + this.supplementInfoId(rec.getUserId(),rec); + getRecords.add(rec); + } + } + result.setSuccess(true); + result.setData(getRecords); + + }else { + result.setSuccess(false); + result.setMessage("UserInfo API return error:["+resultCode+"] "+resultObj.getStatusDescription()); + } + }else { + result.setSuccess(false); + result.setMessage("Invalid return data"); + } + }catch(Exception err) { + result.setSuccess(false); + result.setMessage("Parse return data failed:"+err.getMessage()); + } + + }else { + result.setSuccess(false); + result.setMessage("Invoke get user info failed:["+httpResult.getStatusCode()+"] "+httpResult.getErrorMessage()); + } + }catch(Exception err) { + result.setSuccess(false); + result.setMessage("Invoke get user info API error:"+err.getMessage()); + } + + return result; + } + + public BaseApiResponse checkApprover(String userId,String userName,String roomType,String property) { + BaseApiResponse result = new BaseApiResponse<>(); + try { + HttpResponseResult httpResult = mgmApiService.invokeCheckApprover(userId,userName,roomType,property); + if(httpResult.getStatusCode()==200) { + try { + CheckApproverResult resultObj = JSONObject.parseObject(httpResult.getResponseContent(),CheckApproverResult.class,Feature.SupportNonPublicField,Feature.IgnoreNotMatch); + if(resultObj!=null && resultObj.getStatusCode()!=null) { + String resultCode = resultObj.getStatusCode(); + if("OK".equals(resultCode)) { + if(!"NULL".equals(resultObj.getUserId())) { + result.setSuccess(true); + result.setData(resultObj); + }else { + result.setSuccess(false); + result.setMessage("Approver not found"); + } + }else { + result.setSuccess(false); + result.setMessage("CheckApprover API return error:["+resultCode+"] "+resultObj.getStatusDescription()); + } + }else { + result.setSuccess(false); + result.setMessage("Invalid return data"); + } + }catch(Exception err) { + result.setSuccess(false); + result.setMessage("Parse return data failed:"+err.getMessage()); + } + + }else { + result.setSuccess(false); + result.setMessage("Invoke get approver failed:["+httpResult.getStatusCode()+"] "+httpResult.getErrorMessage()); + } + }catch(Exception err) { + result.setSuccess(false); + result.setMessage("Invoke get approver API error:"+err.getMessage()); + } + + return result; + } + + private UserInfoApiRecord supplementInfoId(String userId,UserInfoApiRecord info) { + // 待完善,有可能需要一层一层获得property,division,department,team + CfgProperties property = propertyDao.getByName(info.getProperty()); + if(property!=null) { + info.setPropertyId(property.getId()); + } + CfgBlocks block = blockDao.getByName(info.getBlock()); + if(block!=null) { + info.setBlockId(block.getId()); + } + CfgDivisions division = divisionDao.getByName(info.getDivision()); + if(division!=null) { + info.setDivisionId(division.getId()); + } + CfgDepartments department = departmentDao.getByName(info.getDepartment()); + if(department!=null) { + info.setDepartmentId(department.getId()); + } + CfgSections section = sectionDao.getByName(info.getSection()); + if(section!=null) { + info.setSectionId(section.getId()); + } + CfgTeamStructure team = teamStructureDao.getByDivisionIdAndDepartmentIdAndSectionId(info.getDivisionId(),info.getDepartmentId(),info.getSectionId()); + if(team!=null) { + info.setTeamStructureId(team.getId()); + } + SysUserView userGroup = sysUserViewDao.getByLoginId(userId); + if(userGroup!=null) { + if(userGroup.getGroupId()!=null) { + info.setGroupName(userGroup.getGroupName()); + List permission = sysGroupPermissionDao.getAllByGroupId(userGroup.getGroupId()); + if(!permission.isEmpty()) { + for(SysGroupPermission per:permission) { + if(SysConstants.PERMISSION_APP_VIEW_BOOKING.equals(per.getPermissionId())) info.setCanViewBooking(true); + if(SysConstants.PERMISSION_APP_NEW_BOOKING.equals(per.getPermissionId())) info.setCanNewBooking(true); + if(SysConstants.PERMISSION_APP_TODO_LIST.equals(per.getPermissionId())) info.setCanViewTodoList(true); + if(SysConstants.PERMISSION_APP_DASHBOARD.equals(per.getPermissionId())) info.setCanViewDashboard(true); + if(SysConstants.PERMISSION_APP_APPROVAL.equals(per.getPermissionId())) info.setCanViewApproval(true); + } + } + } + } + return info; + } +} diff --git a/src/main/java/com/mgm/mcrm/authorization/services/SysGroupPermissionService.java b/src/main/java/com/mgm/mcrm/authorization/services/SysGroupPermissionService.java new file mode 100644 index 0000000..b1ee4c5 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/services/SysGroupPermissionService.java @@ -0,0 +1,90 @@ +package com.mgm.mcrm.authorization.services; + +import com.google.gson.Gson; +import com.mgm.mcrm.authorization.models.SysGroupPermission; +import com.mgm.mcrm.authorization.models.SysRouterPermission; +import com.mgm.mcrm.authorization.repositories.SysGroupDataPermissionDao; +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 jakarta.annotation.Resource; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +public class SysGroupPermissionService { + + @Resource + private SysGroupPermissionDao sysGroupPermissionDao; + @Resource + private SysRouterPermissionDao routerPermissionDao; + @Resource + private SysGroupDataPermissionDao sysGroupDataDao; + + public List getGroupPermissionsByGroupId(long groupId){ + return sysGroupPermissionDao.getAllByGroupId(groupId); + } + + public List getGroupAccessRoomIds(String routerId, String groupName) { + Gson gson = new Gson(); + List propertyIds = new ArrayList<>(); + String[] names = groupName.split(";"); + List groupNameList = new ArrayList<>(); + for(String nameVal:names) { + groupNameList.add(nameVal.trim().toUpperCase()); + } + LogUtil.info(BookingService.class, + "[getGroupAccessRoomIds] groupNameList " + gson.toJson(groupNameList)); + if(!groupNameList.isEmpty()) { + List dataIds =sysGroupDataDao.queryAccessDataByGroupNameAndType(groupNameList, routerId, "ROOM"); + if(dataIds!=null) { + for(String dataId:dataIds) { + try { + Long idVal = Long.parseLong(dataId); + propertyIds.add(idVal); + }catch(Exception ignored) { + + } + } + } + } + + if(propertyIds.isEmpty()) { + propertyIds.add(-1L); + } + return propertyIds; + } + + public List getRouterPermissionsByGroupName(String groupName) { + List groupPermissions = new ArrayList<>(); + if(StringUtils.isNotBlank(groupName)) { + List groupNameList = new ArrayList<>(); + String[] names = groupName.split(";"); + for(String nameVal:names) { + groupNameList.add(nameVal.trim().toUpperCase()); + } + if(!groupNameList.isEmpty()) { + groupPermissions = getRouterPermissionsByGroupNameList(groupNameList); + } + } + return groupPermissions; + } + + public boolean checkGroupPermission(String groupName,String routerPermissionsId) { + List userPermissions = this.getRouterPermissionsByGroupName(groupName); + if(!userPermissions.isEmpty()) { + for(SysRouterPermission per:userPermissions) { + if(Strings.CS.equals(per.getId(), routerPermissionsId) ) return true; + } + } + return false; + } + private List getRouterPermissionsByGroupNameList(List groupNameList) { + return routerPermissionDao.queryPermssionByGroupNameList(groupNameList); + } +} diff --git a/src/main/java/com/mgm/mcrm/authorization/services/UserTokenService.java b/src/main/java/com/mgm/mcrm/authorization/services/UserTokenService.java new file mode 100644 index 0000000..aadc406 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/services/UserTokenService.java @@ -0,0 +1,89 @@ +package com.mgm.mcrm.authorization.services; + +import com.auth0.jwt.JWT; +import com.mgm.mcrm.authorization.models.Token; +import com.mgm.mcrm.authorization.repositories.TokenDao; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; + +@Service +@RequiredArgsConstructor +public class UserTokenService { + private final TokenDao tokenDao; + + @Transactional + public Token saveToken(Token token){ + if(token!=null){ + if(token.getCreatedAt()==null){ + token.setCreatedAt(LocalDateTime.now()); + } + tokenDao.save(token); + } + return token; + } + + public Token getToken(String token) { + Token result=null; + try { + String uuid = JWT.decode(token).getId(); + if (StringUtils.isNotBlank(uuid)) { + result = tokenDao.findByUuid(uuid); + } + }catch(Exception ignored){ + + } + return result; + } + + @Transactional + public Token updateTokenByUniqueId(String tokenUuid, int tokenType, Token newToken) { + if(StringUtils.isBlank(tokenUuid) || newToken==null){ + return saveToken(newToken); + } + Token dbToken = tokenDao.findByUuidAndTokenType(tokenUuid, tokenType); + + if(dbToken==null){ + return saveToken(newToken); + } + + Token newDbToken = new Token(); + + newDbToken.setUuid(newToken.getUuid()); + newDbToken.setToken(newToken.getToken()); + newDbToken.setTokenType(newToken.getTokenType()); + newDbToken.setExpireTime(newToken.getExpireTime()); + newDbToken.setCreatedAt(LocalDateTime.now()); + newDbToken.setUpdatedBy(newToken.getCreatedBy()); + newDbToken.setUpdatedBy(newToken.getCreatedBy()); + newDbToken.setUpdatedAt(LocalDateTime.now()); + newDbToken.setTokenType(tokenType); + return tokenDao.save(newDbToken); + } + + public int deleteToken(String token) { + try{ + if (StringUtils.isBlank(token)) return 0; + String uuid = JWT.decode(token).getId(); + return tokenDao.deleteByUuidAndTokenType(uuid, 1); + } catch (Exception e) { + return 0; + } + } + public int clearTokenByUser(String userId, int tokenType){ + if(StringUtils.isNotBlank(userId)){ + return tokenDao.deleteByUserIdAndTokenType(userId,tokenType); + } + + return 0; + } + + public void removeTokenByUniqueId(String tokenUuid,int tokenType) { + if(StringUtils.isNotBlank(tokenUuid)){ + tokenDao.deleteByUuidAndTokenType(tokenUuid, tokenType); + } + } +} diff --git a/src/main/java/com/mgm/mcrm/authorization/utils/JwtTokenUtil.java b/src/main/java/com/mgm/mcrm/authorization/utils/JwtTokenUtil.java new file mode 100644 index 0000000..3b567f1 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/authorization/utils/JwtTokenUtil.java @@ -0,0 +1,142 @@ +package com.mgm.mcrm.authorization.utils; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.JWTVerificationException; +import com.auth0.jwt.exceptions.SignatureVerificationException; +import com.auth0.jwt.interfaces.DecodedJWT; +import com.mgm.mcrm.authorization.dtos.LoginUserInfo; +import com.mgm.mcrm.authorization.models.Token; +import com.mgm.mcrm.authorization.services.MgmUserService; +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.utils.LogUtil; +import jakarta.servlet.http.HttpServletRequest; +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.StringUtils; + +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.UUID; + +public class JwtTokenUtil { + + @Setter + @Getter + private static String secretKey; + + @Setter + @Getter + private static int accessTokenExpiration=5; + + @Setter + @Getter + private static int appSessionExpiration=30; + + @Setter + @Getter + private static int cmsSessionExpiration=30; + + private static JWTVerifier verifier=null; + + public static JWTVerifier getJwtVerifier(){ + if(verifier==null){ + verifier = JWT.require(Algorithm.HMAC256(secretKey)).build(); + } + return verifier; + } + + public static Token generateTokenByLoginUser(String issueSource, LoginUserInfo user, int tokenType, boolean isRefreshToken) { + int tokeExpiration = isRefreshToken? + (tokenType==1?appSessionExpiration:cmsSessionExpiration) + :accessTokenExpiration; + Instant now = Instant.now(); + Instant expDate = now.plus(Duration.ofMinutes(tokeExpiration)); + String uuid = UUID.randomUUID().toString().replace("-",""); + + String tokenString = JWT.create() + .withIssuer(issueSource) + .withIssuedAt(now).withNotBefore(now).withExpiresAt(expDate).withJWTId(uuid) + .withClaim("login_id", user.getLoginId()) + .withClaim("group_name", user.getGroupName()) + .withClaim("last_post_time", now) + .withSubject(String.valueOf(user.getLoginId())) + .sign(Algorithm.HMAC256(secretKey)); + + Token token = new Token(); + token.setUuid(uuid); + token.setTokenType(tokenType); + token.setToken(tokenString); + token.setExpireTime(LocalDateTime.ofInstant(expDate, ZoneId.systemDefault())); + token.setCreatedBy(user.getLoginId()); + token.setCreatedAt(LocalDateTime.now()); + + return token; + } + + public static LoginUserInfo parseUserFromRequest(HttpServletRequest request) { + LoginUserInfo loginUser = null; + String token = request.getHeader("Authorization"); + if(StringUtils.isNotBlank(token)) { + try { + if(StringUtils.isNotBlank(token) && token.startsWith("Bearer ")){ + token = token.substring(7); + } + loginUser = parseUserFromToken(token); + }catch(Exception err) { + LogUtil.error(SysCommon.class, "Parse Token failed:"+err.getMessage()); + } + } + return loginUser; + } + + public static LoginUserInfo parseUserFromToken(String tokenContent) { + LoginUserInfo loginUser = null; + if(StringUtils.isNotBlank(tokenContent)) { + try { + DecodedJWT decodeData = JWT.decode(tokenContent); + loginUser = new LoginUserInfo(); + String userId = decodeData.getSubject(); + if(StringUtils.isNotBlank(userId)) { + loginUser.setId(Long.valueOf(userId)); + }else { + loginUser.setId(-1L); + } + loginUser.setLoginId(decodeData.getClaim("login_id").asString()); + loginUser.setGroupName(decodeData.getClaim("user_group").asString()); + loginUser.setTokenUuid(decodeData.getId()); + }catch(Exception err) { + LogUtil.error(SysCommon.class, "Parse Token failed:"+err.getMessage()); + loginUser =null; + } + } + return loginUser; + } + + public static boolean checkToken(String token,String clientId) { + if(token!=null) { + // 验证 token + JWTVerifier jwtVerifier = getJwtVerifier(); + try { + jwtVerifier.verify(token); + } + catch (SignatureVerificationException e) { + LogUtil.error(MgmUserService.class, "[checkToken] SignatureVerificationException \nException Message:" + e.getMessage()); + return false; + } + catch (JWTVerificationException e) { + LogUtil.error(MgmUserService.class, "[checkToken] JWTVerificationException \nException Message:" + e.getMessage()); + return false; + } + catch (Exception e) { + LogUtil.error(MgmUserService.class, "[checkToken] Exception \nException Message:" + e.getMessage()); + return false; + } + return true; + } + return false; + } +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/agebucket/models/SysAgebucket.java b/src/main/java/com/mgm/mcrm/basesetting/agebucket/models/SysAgebucket.java new file mode 100644 index 0000000..5dbbab9 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/agebucket/models/SysAgebucket.java @@ -0,0 +1,30 @@ +package com.mgm.mcrm.basesetting.agebucket.models; + +import java.io.Serializable; + +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 lombok.Data; + +@Data +@Entity +@Table(name="sys_agebucket") +public class SysAgebucket implements Serializable { + //fields in table + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="code") + private String code; + @Column(name="dl_agebucket_id") + private String dlAgeBucketId; + + @Column(name = "dl_property_id") + private String dlPropertyId; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/agebucket/repositories/SysAgebucketDao.java b/src/main/java/com/mgm/mcrm/basesetting/agebucket/repositories/SysAgebucketDao.java new file mode 100644 index 0000000..37ad9ca --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/agebucket/repositories/SysAgebucketDao.java @@ -0,0 +1,12 @@ +package com.mgm.mcrm.basesetting.agebucket.repositories; + + +import com.mgm.mcrm.basesetting.agebucket.models.SysAgebucket; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +public interface SysAgebucketDao extends JpaRepository { + + @Query(value = "select * from sys_agebucket where code = ?1 and dl_property_id = ?2",nativeQuery = true) + SysAgebucket getByCodeAndDLPropertyId(String code, String dlPropertyId); +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/agebucket/services/AgebucketService.java b/src/main/java/com/mgm/mcrm/basesetting/agebucket/services/AgebucketService.java new file mode 100644 index 0000000..94aab54 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/agebucket/services/AgebucketService.java @@ -0,0 +1,69 @@ +package com.mgm.mcrm.basesetting.agebucket.services; + +import com.mgm.mcrm.basesetting.agebucket.models.SysAgebucket; +import com.mgm.mcrm.basesetting.agebucket.repositories.SysAgebucketDao; +import com.mgm.mcrm.basesetting.daylight.dtos.response.AgebucketResponse; +import com.mgm.mcrm.basesetting.daylight.services.DaylightService; +import jakarta.annotation.Resource; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static org.apache.commons.collections4.CollectionUtils.*; + +@Service +public class AgebucketService { + + @Lazy + @Resource + private DaylightService daylightService; + @Resource + private SysAgebucketDao sysAgebucketDao; + + public void syncDaylightAgebuckets(String dlPropertyId) { + + List agebucketResponses = daylightService.daylightAgebucketResponseList(dlPropertyId); + if (isEmpty(agebucketResponses)) { + return; + } + + List existingBuckets = sysAgebucketDao.findAll(); + Map existingMap = existingBuckets.stream() + .collect(Collectors.toMap(SysAgebucket::getCode, Function.identity())); + + List bucketsToSave = new ArrayList<>(); + + for (AgebucketResponse agebucketResponse : agebucketResponses) { + SysAgebucket existing = existingMap.get(agebucketResponse.getCode()); + + if (existing != null) { + // 只更新需要同步的字段,避免重复设置 + existing.setDlAgeBucketId(agebucketResponse.getId()); + existing.setDlPropertyId(dlPropertyId); + // 如果有其他需要同步的字段,可以在这里添加 + bucketsToSave.add(existing); + } else { + SysAgebucket newBucket = new SysAgebucket(); + newBucket.setCode(agebucketResponse.getCode()); + newBucket.setDlAgeBucketId(agebucketResponse.getId()); + newBucket.setDlPropertyId(dlPropertyId); + // 设置其他必要字段 + bucketsToSave.add(newBucket); + } + } + + if (!bucketsToSave.isEmpty()) { + sysAgebucketDao.saveAll(bucketsToSave); + } + } + + public SysAgebucket getSysAgebucket(String dlPropertyId) { + syncDaylightAgebuckets(dlPropertyId); + return sysAgebucketDao.getByCodeAndDLPropertyId("ADULT", dlPropertyId); + } +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/ProfileDetail.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/ProfileDetail.java new file mode 100644 index 0000000..256d545 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/ProfileDetail.java @@ -0,0 +1,14 @@ +package com.mgm.mcrm.basesetting.daylight.dtos; + +import lombok.Data; + +@Data +public class ProfileDetail { + + private String firstName; + private String lastName; + +// private VipCode vipCode; + + private String vipCode; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/ProfileMemberships.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/ProfileMemberships.java new file mode 100644 index 0000000..d1e4f78 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/ProfileMemberships.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.basesetting.daylight.dtos; + +import lombok.Data; + +@Data +public class ProfileMemberships { + + private String typecode; + private LevelCode levelCode; + private String number; + private String id; + + @Data + public static class LevelCode { + private String id; + private String code; + private String description; + } +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/VipCode.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/VipCode.java new file mode 100644 index 0000000..9cbe7ae --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/VipCode.java @@ -0,0 +1,15 @@ +package com.mgm.mcrm.basesetting.daylight.dtos; + +import lombok.Data; + +@Data +public class VipCode { + + private String id; + + private String code; + + private String description; + + private String languageCode; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/request/AmountLimit.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/request/AmountLimit.java new file mode 100644 index 0000000..0183182 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/request/AmountLimit.java @@ -0,0 +1,13 @@ +package com.mgm.mcrm.basesetting.daylight.dtos.request; + +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class AmountLimit { + + private BigDecimal amount; + + private String currency; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/request/CompRuleDateRange.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/request/CompRuleDateRange.java new file mode 100644 index 0000000..dc69d41 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/request/CompRuleDateRange.java @@ -0,0 +1,10 @@ +package com.mgm.mcrm.basesetting.daylight.dtos.request; + +import lombok.Data; + +@Data +public class CompRuleDateRange { + + private String start; + private String end; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/request/ComplimentaryRuleLimits.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/request/ComplimentaryRuleLimits.java new file mode 100644 index 0000000..b162c60 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/request/ComplimentaryRuleLimits.java @@ -0,0 +1,18 @@ +package com.mgm.mcrm.basesetting.daylight.dtos.request; + +import lombok.Data; + +import java.util.List; + +@Data +public class ComplimentaryRuleLimits { + + List dateRanges; + + private AmountLimit totalAmountLimit; + + private AmountLimit softTotalAmountLimit; + + private List limitExcludedPresetIds; +} + diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/request/CreateCompRuleRequest.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/request/CreateCompRuleRequest.java new file mode 100644 index 0000000..1a55a6e --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/request/CreateCompRuleRequest.java @@ -0,0 +1,30 @@ +package com.mgm.mcrm.basesetting.daylight.dtos.request; + +import lombok.Data; + +import java.util.List; + +@Data +public class CreateCompRuleRequest { + + private String complimentaryTypeId; + + private String paymentMethodTransactionCodeId; + + private boolean isExecutive; + + private boolean doNotIssueInvoice; + + private String profileId; + + private List complimentaryAccountingPresetsIds; + + private String justification; + + private String requestorId; + + private String approverId; + + private ComplimentaryRuleLimits complimentaryRuleLimits; + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/request/UpdateCompRuleRequest.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/request/UpdateCompRuleRequest.java new file mode 100644 index 0000000..5bb0e8f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/request/UpdateCompRuleRequest.java @@ -0,0 +1,13 @@ +package com.mgm.mcrm.basesetting.daylight.dtos.request; + +import lombok.Data; + +@Data +public class UpdateCompRuleRequest { + + private String justification; + + private String requestorId; + + private ComplimentaryRuleLimits complimentaryRuleLimits; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/AccountResponse.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/AccountResponse.java new file mode 100644 index 0000000..7fab386 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/AccountResponse.java @@ -0,0 +1,27 @@ +package com.mgm.mcrm.basesetting.daylight.dtos.response; + +import lombok.Data; + +@Data +public class AccountResponse { + + private String id; + + private Integer version; + + private String profileId; + + private CodeDescription channelCode; + + private CodeDescription sourceCode; + + private CodeDescription marketSegmentCode; + + @Data + public static class CodeDescription { + + private String code; + + private String description; + } +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/AgebucketResponse.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/AgebucketResponse.java new file mode 100644 index 0000000..2ecdff5 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/AgebucketResponse.java @@ -0,0 +1,16 @@ +package com.mgm.mcrm.basesetting.daylight.dtos.response; + +import com.alibaba.fastjson.annotation.JSONField; +import com.mgm.mcrm.basesetting.property.dtos.response.DescriptionResponse; +import lombok.Data; + +import java.util.List; + +@Data +public class AgebucketResponse { + + private String id; + private String code; + @JSONField(name = "description") + private List descriptions; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/CancelReasonResponse.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/CancelReasonResponse.java new file mode 100644 index 0000000..ce1da6d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/CancelReasonResponse.java @@ -0,0 +1,13 @@ +package com.mgm.mcrm.basesetting.daylight.dtos.response; + +import lombok.Data; + +@Data +public class CancelReasonResponse { + + private String id; + + private String code; + + private String enContent; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/ProfileDetailResponse.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/ProfileDetailResponse.java new file mode 100644 index 0000000..263bd69 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/ProfileDetailResponse.java @@ -0,0 +1,28 @@ +package com.mgm.mcrm.basesetting.daylight.dtos.response; + +import com.mgm.mcrm.basesetting.daylight.dtos.ProfileMemberships; +import com.mgm.mcrm.basesetting.daylight.dtos.VipCode; +import lombok.Data; + +import java.util.List; + +@Data +public class ProfileDetailResponse { + + private String id; + + private ProfileDetailInProfileDetailResponse details; + + private Integer version; + + private List memberships; + + private String customFieldContainerJson; + + @Data + public static class ProfileDetailInProfileDetailResponse { + private String firstName; + private String lastName; + private VipCode vipCode; + } +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/RequestorApproverResponse.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/RequestorApproverResponse.java new file mode 100644 index 0000000..76c3c02 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/RequestorApproverResponse.java @@ -0,0 +1,17 @@ +package com.mgm.mcrm.basesetting.daylight.dtos.response; + +import lombok.Data; + +@Data +public class RequestorApproverResponse { + + private String id; + + private String firstName; + + private String lastName; + + private String code; + + private Integer version; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/ReservationDoorKeyResponse.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/ReservationDoorKeyResponse.java new file mode 100644 index 0000000..c871e58 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/ReservationDoorKeyResponse.java @@ -0,0 +1,11 @@ +package com.mgm.mcrm.basesetting.daylight.dtos.response; + +import lombok.Data; + +@Data +public class ReservationDoorKeyResponse { + + private String id; + + private boolean hasKey; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/ReservationNoteResponse.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/ReservationNoteResponse.java new file mode 100644 index 0000000..09c0be0 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/ReservationNoteResponse.java @@ -0,0 +1,15 @@ +package com.mgm.mcrm.basesetting.daylight.dtos.response; + +import lombok.Data; + +@Data +public class ReservationNoteResponse { + + private String noteId; + + private String content; + + private String typeCode; + + private Integer version; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/ReservationQueueResponse.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/ReservationQueueResponse.java new file mode 100644 index 0000000..b588cff --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/dtos/response/ReservationQueueResponse.java @@ -0,0 +1,11 @@ +package com.mgm.mcrm.basesetting.daylight.dtos.response; + +import lombok.Data; + +@Data +public class ReservationQueueResponse { + + private String id; + + private boolean isQueue; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgBlockCodes.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgBlockCodes.java new file mode 100644 index 0000000..f0e14eb --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgBlockCodes.java @@ -0,0 +1,53 @@ +package com.mgm.mcrm.basesetting.daylight.models; + +import java.io.Serializable; +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 com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +@Data +@Entity +@Table(name = "cfg_block_codes") +public class CfgBlockCodes implements Serializable { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name = "block_id") + private Long blockId; + @Column(name = "code") + private String code; + @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; + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + @Column(name = "start_date") + private Date startDate; + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + @Column(name = "end_date") + private Date endDate; + @Column(name = "source_name") + private String sourceName; + + @Column(name = "dl_block_id") + private String dlBlockId; + + @Column(name = "category") + private String category; + + @Column(name = "property_id") + private Integer propertyId; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgCompPreset.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgCompPreset.java new file mode 100644 index 0000000..a2863d2 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgCompPreset.java @@ -0,0 +1,24 @@ +package com.mgm.mcrm.basesetting.daylight.models; + +import jakarta.persistence.*; +import lombok.Data; + +@Data +@Entity +@Table(name = "cfg_comp_preset") +public class CfgCompPreset { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "daylight_mapping_id") + private Integer daylightMappingId; + + @Column(name = "dl_comp_preset_id") + private String dlCompPresetId; + + @Column(name = "comp_preset_content") + private String compPresetContent; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgDaylightConfiguration.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgDaylightConfiguration.java new file mode 100644 index 0000000..1a3de4c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgDaylightConfiguration.java @@ -0,0 +1,32 @@ +package com.mgm.mcrm.basesetting.daylight.models; + +import jakarta.persistence.*; +import lombok.Data; + +import java.util.Date; + +@Data +@Entity +@Table(name = "cfg_daylight_configuration") +public class CfgDaylightConfiguration { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "config_name") + private String configName; + + @Column(name = "config_value") + private String configValue; + + @Column(name = "dl_property_id") + private String dlPropertyId; + + @Column(name = "created_at") + private Date createdAt; + + @Column(name = "updated_at") + private Date updatedAt; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgDaylightMapping.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgDaylightMapping.java new file mode 100644 index 0000000..af946d9 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgDaylightMapping.java @@ -0,0 +1,70 @@ +package com.mgm.mcrm.basesetting.daylight.models; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +import jakarta.persistence.*; +import lombok.Data; + +@Data +@Entity +@Table(name = "cfg_daylight_mapping") +public class CfgDaylightMapping implements Serializable { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name = "section_id") + private Long sectionId; + @Column(name = "property_id") + private Long propertyId; + @Column(name = "booking_type_id") + private Long bookingTypeId; + @Column(name = "rate_code_id") + private Long rateCodeId; + @Column(name = "source_code_id") + private Long sourceCodeId; + @Column(name = "market_code_id") + private Long marketCodeId; + @Column(name = "block_code_id") + private Long blockCodeId; + @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 = "soft_limit") + private String softLimit; + + @Column(name = "approver") + private String approver; + + @Column(name = "comp_rule_category") + private Integer compRuleCategory; + + @Column(name = "dl_comp_type_id") + private String dlCompTypeId; + + @Column(name = "comp_type_content") + private String compTypeContent; + + @OneToMany(fetch = FetchType.LAZY) + @JoinColumn(name = "daylight_mapping_id", insertable = false, updatable = false) + private List cfgCompPresetList; + + @Column(name = "dl_payment_method_code_id") + private String dlPaymentMethodCodeId; + + @Column(name = "payment_method_code_content") + private String paymentMethodCodeContent; + + @Transient + private List roomTypeIds; + @Transient + private List blockCodeIds; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgDaylightView.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgDaylightView.java new file mode 100644 index 0000000..eae0643 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgDaylightView.java @@ -0,0 +1,156 @@ +package com.mgm.mcrm.basesetting.daylight.models; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; +import java.util.Set; + +import com.mgm.mcrm.basesetting.property.models.CfgProperties; +import com.mgm.mcrm.basesetting.room.models.CfgRoomTypes; +import com.mgm.mcrm.basesetting.team.models.CfgDepartments; +import com.mgm.mcrm.basesetting.team.models.CfgDivisions; +import com.mgm.mcrm.basesetting.team.models.CfgSections; +import com.mgm.mcrm.booking.models.CfgBookingTypes; +import jakarta.persistence.*; + +import lombok.Data; +import org.hibernate.annotations.NotFound; +import org.hibernate.annotations.NotFoundAction; + +@Data +@Entity +@Table(name="view_daylight") +@NamedEntityGraph( + name = "graph.DaylightMapping.fulldetails", + attributeNodes = { + @NamedAttributeNode("section"), + @NamedAttributeNode("property"), + @NamedAttributeNode("bookingType"), + @NamedAttributeNode("rateCode"), + @NamedAttributeNode("sourceCode"), + @NamedAttributeNode("marketCode"), + @NamedAttributeNode("daylightRoomType"), + @NamedAttributeNode("cfgCompPresetList") + } +) +public class CfgDaylightView implements Serializable { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="section_id") + private Long sectionId; + @Column(name="property_id") + private Long propertyId; + @Column(name="booking_type_id") + private Long bookingTypeId; + @Column(name="rate_code_id") + private Long rateCodeId; + @Column(name="source_code_id") + private Long sourceCodeId; + @Column(name="market_code_id") + private Long marketCodeId; + @Column(name="block_code_id") + private Long blockCodeId; + @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="block_code_name") + private String blockCodeName; + @Column(name="start_date") + private String startDate; + @Column(name="end_date") + private String endDate; + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="section_id",insertable=false ,updatable=false) + private CfgSections section; + + @Column(name = "approver") + private String approver; + + @Column(name = "comp_rule_category") + private Integer compRuleCategory; + + @Column(name = "dl_comp_type_id") + private String dlCompTypeId; + + @Column(name = "comp_type_content") + private String compTypeContent; + + @OneToMany(fetch = FetchType.LAZY) + @JoinColumn(name = "daylight_mapping_id", insertable = false, updatable = false) + private List cfgCompPresetList; + + @Column(name = "dl_payment_method_code_id") + private String dlPaymentMethodCodeId; + + @Column(name = "payment_method_code_content") + private String paymentMethodCodeContent; + + @Column(name = "soft_limit") + private String softLimit; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="property_id",insertable=false ,updatable=false) + private CfgProperties property; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="booking_type_id",insertable=false ,updatable=false) + private CfgBookingTypes bookingType; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="rate_code_id",insertable=false ,updatable=false) + private CfgRateCodes rateCode; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="block_code_id",insertable=false ,updatable=false) + private CfgBlockCodes blockCode; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="source_code_id",insertable=false ,updatable=false) + private CfgSourceCodes sourceCode; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="market_code_id",insertable=false ,updatable=false) + private CfgMarketCodes marketCode; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name="cfg_daylight_mapping_room_types",joinColumns={@JoinColumn(name="daylight_id")},inverseJoinColumns={@JoinColumn(name="room_type_id")}) + private Set daylightRoomType; + + //-- For export + @Transient + private String divisionName; + @Transient + private String departmentName; + @Transient + private String sectionName; + @Transient + private String propertyName; + @Transient + private String bookingTypeName; + @Transient + private String blockName; + @Transient + private String rateCodeName; + @Transient + private String roomTypeNames; + @Transient + private String sourceCodeName; + @Transient + private String marketCodeName; + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgExceptDaylightRoomTypes.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgExceptDaylightRoomTypes.java new file mode 100644 index 0000000..7a82371 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgExceptDaylightRoomTypes.java @@ -0,0 +1,28 @@ +package com.mgm.mcrm.basesetting.daylight.models; + +import java.io.Serializable; +import java.util.Date; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.Table; +import lombok.Data; + +@Data +@Entity +@Table(name="cfg_except_daylight_room_types") +@IdClass(CfgExceptionDaylightRoomTypesKey.class) +public class CfgExceptDaylightRoomTypes implements Serializable { + @Id + @Column(name="except_daylight_id") + private Long exceptDaylightId; + @Id + @Column(name="room_type_id") + private Long roomTypeId; + @Column(name="created_at") + private Date createdAt; + @Column(name="created_by") + private String createdBy; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgExceptionDaylight.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgExceptionDaylight.java new file mode 100644 index 0000000..b6b95a6 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgExceptionDaylight.java @@ -0,0 +1,50 @@ +package com.mgm.mcrm.basesetting.daylight.models; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +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.Transient; +import lombok.Data; + +@Data +@Entity +@Table(name="cfg_exception_daylight") +public class CfgExceptionDaylight implements Serializable { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="user_id") + private String userId; + @Column(name="property_id") + private Long propertyId; + @Column(name="booking_type_id") + private Long bookingTypeId; + @Column(name="rate_code_id") + private Long rateCodeId; + @Column(name="source_code_id") + private Long sourceCodeId; + @Column(name="market_code_id") + private Long marketCodeId; + @Column(name="block_code_id") + private Long blockCodeId; + @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; + @Transient + private List roomTypeIds; + @Transient + private List blockCodeIds; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgExceptionDaylightRoomTypesKey.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgExceptionDaylightRoomTypesKey.java new file mode 100644 index 0000000..a1fb31c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgExceptionDaylightRoomTypesKey.java @@ -0,0 +1,36 @@ +package com.mgm.mcrm.basesetting.daylight.models; + +import lombok.Getter; +import lombok.Setter; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Objects; + +@Setter +@Getter +public class CfgExceptionDaylightRoomTypesKey implements Serializable { + + @Serial + private static final long serialVersionUID = 6060166117433738173L; + private Long exceptDaylightId; + private Long roomTypeId; + + + @Override + public boolean equals(Object o) { + if (o instanceof CfgExceptionDaylightRoomTypesKey key) { + if (Objects.equals(this.exceptDaylightId, key.getExceptDaylightId()) && + Objects.equals(this.roomTypeId, key.getRoomTypeId())) { + return true; + } + } + return false; + } + + @Override + public int hashCode() { + return 1; + } + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgExceptionDaylightView.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgExceptionDaylightView.java new file mode 100644 index 0000000..a2e6fd2 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgExceptionDaylightView.java @@ -0,0 +1,150 @@ +package com.mgm.mcrm.basesetting.daylight.models; + +import java.io.Serializable; +import java.util.Date; +import java.util.Set; + +import com.mgm.mcrm.basesetting.property.models.CfgProperties; +import com.mgm.mcrm.basesetting.room.models.CfgRoomTypes; +import jakarta.persistence.*; + +import lombok.Data; +import org.hibernate.annotations.NotFound; +import org.hibernate.annotations.NotFoundAction; +import com.mgm.mcrm.booking.models.CfgBookingTypes; + +@Data +@Entity +@Table(name="view_exception_daylight") +@NamedEntityGraph( + name = "graph.ExceptionDaylightMapping.fulldetails", + attributeNodes = { + @NamedAttributeNode("property"), + @NamedAttributeNode("bookingType"), + @NamedAttributeNode("rateCode"), + @NamedAttributeNode("sourceCode"), + @NamedAttributeNode("marketCode"), + @NamedAttributeNode("daylightRoomType") + } +) +public class CfgExceptionDaylightView implements Serializable { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + // SQL查询中的字段 + @Column(name="user_id") + private String userId; + + @Column(name="block_code_id") + private Long blockCodeId; + + @Column(name="property_id") + private Long propertyId; + + @Column(name="booking_type_id") + private Long bookingTypeId; + + @Column(name="rate_code_id") + private Long rateCodeId; + + @Column(name="source_code_id") + private Long sourceCodeId; + + @Column(name="market_code_id") + private Long marketCodeId; + + @Column(name="created_at") + private Date createdAt; + + @Column(name="updated_at") + private Date updatedAt; + + @Column(name="created_by") + private String createdBy; + + @Column(name="updated_by") + private String updatedBy; + + // SQL查询中的连接字段 + @Column(name="start_date") + private Date startDate; + + @Column(name="end_date") + private Date endDate; + + @Column(name="block_code_name") + private String blockCodeName; + + @Column(name="block_id") + private Long blockId; + + // 关联关系 + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="property_id", insertable=false, updatable=false) + private CfgProperties property; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="booking_type_id", insertable=false, updatable=false) + private CfgBookingTypes bookingType; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="rate_code_id", insertable=false, updatable=false) + private CfgRateCodes rateCode; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="block_code_id", insertable=false, updatable=false) + private CfgBlockCodes blockCode; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="source_code_id", insertable=false, updatable=false) + private CfgSourceCodes sourceCode; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="market_code_id", insertable=false, updatable=false) + private CfgMarketCodes marketCode; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable( + name="cfg_except_daylight_room_types", + joinColumns={@JoinColumn(name="except_daylight_id")}, + inverseJoinColumns={@JoinColumn(name="room_type_id")} + ) + private Set daylightRoomType; + + // 以下是已删除的多余字段: + // private String blockCodeName; // SQL查询中没有此字段,使用blockCode字段 + + // 以下是根据SQL查询确认缺少的字段: + // 已全部包含在当前SQL查询中 + + // 对于startDate和endDate字段,建议使用Date类型而不是String类型 + // 因为它们通常是日期类型 + + // 瞬态字段(用于导出) + @Transient + private String propertyName; + + @Transient + private String blockName; + + @Transient + private String rateCodeName; + + @Transient + private String roomTypeNames; + + @Transient + private String sourceCodeName; + + @Transient + private String marketCodeName; +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgExceptionOperaView.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgExceptionOperaView.java new file mode 100644 index 0000000..4307d87 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgExceptionOperaView.java @@ -0,0 +1,136 @@ +package com.mgm.mcrm.basesetting.daylight.models; + +import java.io.Serializable; +import java.util.Date; +import java.util.Set; + +import com.mgm.mcrm.basesetting.property.models.CfgProperties; +import com.mgm.mcrm.basesetting.room.models.CfgRoomTypes; +import jakarta.persistence.*; + +import lombok.Data; +import org.hibernate.annotations.NotFound; +import org.hibernate.annotations.NotFoundAction; +import com.mgm.mcrm.booking.models.CfgBookingTypes; + +@Data +@Entity +@Table(name="view_exception_opera") +@NamedEntityGraph( + name = "graph.ExceptionOperaMapping.fulldetails", + attributeNodes = { + @NamedAttributeNode("property"), + @NamedAttributeNode("bookingType"), + @NamedAttributeNode("rateCode"), + @NamedAttributeNode("sourceCode"), + @NamedAttributeNode("marketCode"), + @NamedAttributeNode("operaRoomType") + } +) +public class CfgExceptionOperaView implements Serializable { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + // SQL查询中的字段 + @Column(name="user_id") + private String userId; + + @Column(name="block_code_id") + private Long blockCodeId; + + @Column(name="property_id") + private Long propertyId; + + @Column(name="booking_type_id") + private Long bookingTypeId; + + @Column(name="rate_code_id") + private Long rateCodeId; + + @Column(name="source_code_id") + private Long sourceCodeId; + + @Column(name="market_code_id") + private Long marketCodeId; + + @Column(name="created_at") + private Date createdAt; + + @Column(name="updated_at") + private Date updatedAt; + + @Column(name="created_by") + private String createdBy; + + @Column(name="updated_by") + private String updatedBy; + + // SQL查询中的连接字段 + @Column(name="start_date") + private Date startDate; + + @Column(name="end_date") + private Date endDate; + + @Column(name="block_code") + private String blockCode; + + @Column(name="block_id") + private Long blockId; + + // 关联关系 + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="property_id", insertable=false, updatable=false) + private CfgProperties property; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="booking_type_id", insertable=false, updatable=false) + private CfgBookingTypes bookingType; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="rate_code_id", insertable=false, updatable=false) + private CfgRateCodes rateCode; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="source_code_id", insertable=false, updatable=false) + private CfgSourceCodes sourceCode; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="market_code_id", insertable=false, updatable=false) + private CfgMarketCodes marketCode; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable( + name="cfg_except_opera_room_types", + joinColumns={@JoinColumn(name="except_opera_id")}, + inverseJoinColumns={@JoinColumn(name="room_type_id")} + ) + private Set operaRoomType; + + // 瞬态字段(用于导出) + @Transient + private String propertyName; + + @Transient + private String blockName; + + @Transient + private String rateCodeName; + + @Transient + private String roomTypeNames; + + @Transient + private String sourceCodeName; + + @Transient + private String marketCodeName; +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgItemInventory.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgItemInventory.java new file mode 100644 index 0000000..5651cfc --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgItemInventory.java @@ -0,0 +1,45 @@ +package com.mgm.mcrm.basesetting.daylight.models; + +import java.io.Serializable; +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 lombok.Data; + +@Data +@Entity +@Table(name="cfg_item_inventory") +public class CfgItemInventory implements Serializable { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="tier_id") + private Long tierId; + @Column(name="property_id") + private Long propertyId; + @Column(name="room_id") + private Long roomId; + @Column(name="amenity_package_code") + private String amenityPackageCode; + @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 = "dl_purchase_element_id") + private String dlPurchaseElementId; + @Column(name = "dl_code") + private String dlCode; + @Column(name = "category") + private String category; +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgMarketCodes.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgMarketCodes.java new file mode 100644 index 0000000..59aaf2f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgMarketCodes.java @@ -0,0 +1,38 @@ +package com.mgm.mcrm.basesetting.daylight.models; + +import java.io.Serializable; +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 lombok.Data; + +@Data +@Entity +@Table(name = "cfg_market_codes") +public class CfgMarketCodes implements Serializable { + //fields in table + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name = "code") + private String code; + @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 = "dl_market_segment_id") + private String dlMarketSegmentId; + + @Column(name = "category") + private String category; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgNonMGMStatusMapping.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgNonMGMStatusMapping.java new file mode 100644 index 0000000..63ab526 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgNonMGMStatusMapping.java @@ -0,0 +1,121 @@ +package com.mgm.mcrm.basesetting.daylight.models; + +import java.util.Date; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; + +import org.hibernate.annotations.NotFound; +import org.hibernate.annotations.NotFoundAction; +import com.mgm.mcrm.basesetting.property.models.CfgProperties; +import com.mgm.mcrm.basesetting.room.models.CfgRooms; + +@Entity +@Table(name="cfg_nonmgm_status_mapping") +public class CfgNonMGMStatusMapping { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="status_code") + private String statusCode; + @Column(name="room_id") + private Long roomId; + @Column(name="property_id") + private Long propertyId; + @Column(name="status_name") + private String statusName; + @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; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="room_id",insertable=false ,updatable=false) + private CfgRooms roomObj; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="property_id",insertable=false ,updatable=false) + private CfgProperties propertyObj; + + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public String getStatusCode() { + return statusCode; + } + public void setStatusCode(String statusCode) { + this.statusCode = statusCode; + } + public String getStatusName() { + return statusName; + } + public void setStatusName(String statusName) { + this.statusName = statusName; + } + public Date getCreatedAt() { + return createdAt; + } + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + public String getCreatedBy() { + return createdBy; + } + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + public Date getUpdatedAt() { + return updatedAt; + } + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + public String getUpdatedBy() { + return updatedBy; + } + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + public CfgRooms getRoomObj() { + return roomObj; + } + public void setRoomObj(CfgRooms roomObj) { + this.roomObj = roomObj; + } + public Long getRoomId() { + return roomId; + } + public void setRoomId(Long roomId) { + this.roomId = roomId; + } + public Long getPropertyId() { + return propertyId; + } + public void setPropertyId(Long propertyId) { + this.propertyId = propertyId; + } + public CfgProperties getPropertyObj() { + return propertyObj; + } + public void setPropertyObj(CfgProperties propertyObj) { + this.propertyObj = propertyObj; + } + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgOperaView.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgOperaView.java new file mode 100644 index 0000000..9b34b3f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgOperaView.java @@ -0,0 +1,145 @@ +package com.mgm.mcrm.basesetting.daylight.models; + +import java.io.Serializable; +import java.util.Date; +import java.util.Set; + +import com.mgm.mcrm.basesetting.property.models.CfgProperties; +import com.mgm.mcrm.basesetting.room.models.CfgRoomTypes; +import jakarta.persistence.*; + +import lombok.Data; +import org.hibernate.annotations.NotFound; +import org.hibernate.annotations.NotFoundAction; +import com.mgm.mcrm.booking.models.CfgBookingTypes; + +@Data +@Entity +@Table(name="view_opera") +@NamedEntityGraph( + name = "graph.OperaMapping.fulldetails", + attributeNodes = { + @NamedAttributeNode("property"), + @NamedAttributeNode("bookingType"), + @NamedAttributeNode("rateCode"), + @NamedAttributeNode("sourceCode"), + @NamedAttributeNode("marketCode"), + @NamedAttributeNode("operaRoomType") + } +) +public class CfgOperaView implements Serializable { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + // SQL查询中的字段 + @Column(name="block_code_id") + private Long blockCodeId; + + @Column(name="division_id") + private Long divisionId; + + @Column(name="team_id") + private Long teamId; + + @Column(name="property_id") + private Long propertyId; + + @Column(name="booking_type_id") + private Long bookingTypeId; + + @Column(name="rate_code_id") + private Long rateCodeId; + + @Column(name="source_code_id") + private Long sourceCodeId; + + @Column(name="market_code_id") + private Long marketCodeId; + + @Column(name="department_id") + private Long departmentId; + + @Column(name="section_id") + private Long sectionId; + + @Column(name="created_at") + private Date createdAt; + + @Column(name="updated_at") + private Date updatedAt; + + @Column(name="created_by") + private String createdBy; + + @Column(name="updated_by") + private String updatedBy; + + // SQL查询中的连接字段 + @Column(name="start_date") + private Date startDate; + + @Column(name="end_date") + private Date endDate; + + @Column(name="block_code") + private String blockCode; + + @Column(name="block_id") + private Long blockId; + + // 关联关系 + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="property_id", insertable=false, updatable=false) + private CfgProperties property; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="booking_type_id", insertable=false, updatable=false) + private CfgBookingTypes bookingType; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="rate_code_id", insertable=false, updatable=false) + private CfgRateCodes rateCode; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="source_code_id", insertable=false, updatable=false) + private CfgSourceCodes sourceCode; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="market_code_id", insertable=false, updatable=false) + private CfgMarketCodes marketCode; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable( + name="cfg_opera_room_types", + joinColumns={@JoinColumn(name="opera_id")}, + inverseJoinColumns={@JoinColumn(name="room_type_id")} + ) + private Set operaRoomType; + + // 瞬态字段(用于导出) - 根据需要保留 + @Transient + private String propertyName; + + @Transient + private String blockName; + + @Transient + private String rateCodeName; + + @Transient + private String roomTypeNames; + + @Transient + private String sourceCodeName; + + @Transient + private String marketCodeName; +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgOtherFollowUpStatus.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgOtherFollowUpStatus.java new file mode 100644 index 0000000..2379abb --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgOtherFollowUpStatus.java @@ -0,0 +1,39 @@ +package com.mgm.mcrm.basesetting.daylight.models; + +import java.io.Serializable; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +@Entity +@Table(name="cfg_other_follow_up_status") +public class CfgOtherFollowUpStatus implements Serializable { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="name") + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgOtherSegment.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgOtherSegment.java new file mode 100644 index 0000000..2a802d8 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgOtherSegment.java @@ -0,0 +1,111 @@ +package com.mgm.mcrm.basesetting.daylight.models; + +import java.io.Serializable; +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.Transient; + +@Entity +@Table(name="cfg_other_segment") +public class CfgOtherSegment implements Serializable { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="name") + private String segmentName; + @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; + + @Transient + private Integer appChannel; + @Transient + private Integer available; + @Transient + private Integer pickedUp; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + public String getSegmentName() { + return segmentName; + } + + public void setSegmentName(String segmentName) { + this.segmentName = segmentName; + } + + public Integer getAppChannel() { + return appChannel; + } + + public void setAppChannel(Integer appChannel) { + this.appChannel = appChannel; + } + + public Integer getAvailable() { + return available; + } + + public void setAvailable(Integer available) { + this.available = available; + } + + public Integer getPickedUp() { + return pickedUp; + } + + public void setPickedUp(Integer pickedUp) { + this.pickedUp = pickedUp; + } + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgRateCodes.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgRateCodes.java new file mode 100644 index 0000000..b489fb1 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgRateCodes.java @@ -0,0 +1,37 @@ +package com.mgm.mcrm.basesetting.daylight.models; + +import java.io.Serializable; +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 lombok.Data; + +@Data +@Entity +@Table(name="cfg_rate_codes") +public class CfgRateCodes implements Serializable { + //fields in table + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="code") + private String code; + @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="dl_rate_plan_id") + private String dlRatePlanId; + @Column(name = "category") + private String category; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgSourceCodes.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgSourceCodes.java new file mode 100644 index 0000000..5a9cab0 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgSourceCodes.java @@ -0,0 +1,35 @@ +package com.mgm.mcrm.basesetting.daylight.models; + +import java.io.Serializable; +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 lombok.Data; + +@Entity +@Data +@Table(name="cfg_source_codes") +public class CfgSourceCodes implements Serializable { + //fields in table + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="code") + private String code; + @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="dl_source_id") + private String dlSourceId; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgTiers.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgTiers.java new file mode 100644 index 0000000..cdfd89a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/models/CfgTiers.java @@ -0,0 +1,40 @@ +package com.mgm.mcrm.basesetting.daylight.models; + +import java.io.Serializable; +import java.util.Date; + +import com.mgm.mcrm.logging.models.SysLogBooking; +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 lombok.Data; + +@Data +@Entity +@Table(name="cfg_tiers") +public class CfgTiers implements Serializable { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="tier_name") + private String tierName; + @Column(name="igt_tier_id") + private String igtTierId; + @Column(name="daylight_tier") + private String daylightTier; + @Column(name = "category") + private String category; + @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; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/BlockCodeDao.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/BlockCodeDao.java new file mode 100644 index 0000000..ac4db12 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/BlockCodeDao.java @@ -0,0 +1,31 @@ +package com.mgm.mcrm.basesetting.daylight.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import com.mgm.mcrm.basesetting.daylight.models.CfgBlockCodes; + + +public interface BlockCodeDao extends JpaRepository { + CfgBlockCodes findById(long id); + List findByCode(String code); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + + CfgBlockCodes findByDlBlockId(String dlBlockId); + + @Transactional + @Modifying + @Query(value = " delete from cfg_block_codes where id=?1 ",nativeQuery=true) + int deleteById(long id); + +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/CompPresetDao.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/CompPresetDao.java new file mode 100644 index 0000000..3bccfd5 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/CompPresetDao.java @@ -0,0 +1,12 @@ +package com.mgm.mcrm.basesetting.daylight.repositories; + +import com.mgm.mcrm.basesetting.daylight.models.CfgCompPreset; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface CompPresetDao extends JpaRepository { + + List findAllByDaylightMappingId(Long daylightMappingId); +} + diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/DaylightConfigurationDao.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/DaylightConfigurationDao.java new file mode 100644 index 0000000..92ddb62 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/DaylightConfigurationDao.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.basesetting.daylight.repositories; + +import com.mgm.mcrm.basesetting.daylight.models.CfgDaylightConfiguration; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Repository +public interface DaylightConfigurationDao extends JpaRepository { + + List findByDlPropertyId(String dlPropertyId); + + CfgDaylightConfiguration findByDlPropertyIdAndConfigName(String dlPropertyId, String configName); + + CfgDaylightConfiguration findFirstByOrderByUpdatedAtDesc(); + + @Transactional + void deleteByDlPropertyId(String dlPropertyId); +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/DaylightDao.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/DaylightDao.java new file mode 100644 index 0000000..c1c2322 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/DaylightDao.java @@ -0,0 +1,27 @@ +package com.mgm.mcrm.basesetting.daylight.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import com.mgm.mcrm.basesetting.daylight.models.CfgDaylightMapping; + +public interface DaylightDao extends JpaRepository { + CfgDaylightMapping findById(long id); + List findAll(Specification spec, Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + + @Transactional + @Modifying + @Query(value = " delete from cfg_daylight_mapping where id=?1 ",nativeQuery=true) + int deleteById(long id); + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/DaylightViewDao.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/DaylightViewDao.java new file mode 100644 index 0000000..2eb1b3c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/DaylightViewDao.java @@ -0,0 +1,52 @@ +package com.mgm.mcrm.basesetting.daylight.repositories; + +import java.util.List; +import java.util.Optional; + +import com.mgm.mcrm.basesetting.team.models.CfgSections; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; +import com.mgm.mcrm.basesetting.daylight.models.CfgDaylightView; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + + +public interface DaylightViewDao extends JpaRepository { + @EntityGraph(value = "graph.DaylightMapping.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + CfgDaylightView findById(long id); + + @EntityGraph(value = "graph.DaylightMapping.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findAll(Specification spec, Sort sort); + + @EntityGraph(value = "graph.DaylightMapping.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findAll(Specification spec); + + Page findAll(Specification spec, Pageable pageable); + + @EntityGraph(value = "graph.DaylightMapping.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findBySectionIdAndPropertyIdAndBookingTypeId(Long sectionId, Long propertyId, Long bookingTypeId); + + @EntityGraph(value = "graph.DaylightMapping.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findByMarketCodeIdAndRateCodeId(Long marketCodeId, Long rateCodeId); + + @EntityGraph(value = "graph.DaylightMapping.fulldetails") + @Query(""" + SELECT d + FROM CfgDaylightView d + JOIN d.daylightRoomType rt + WHERE d.sectionId = :sectionId + AND d.propertyId = :propertyId + AND d.bookingTypeId = :bookingTypeId + AND rt.id = :roomTypeId + """) + List findBySectionPropertyBookingTypeRoomType( + @Param("sectionId") Long sectionId, + @Param("propertyId") Long propertyId, + @Param("bookingTypeId") Long bookingTypeId, + @Param("roomTypeId") Long roomTypeId + ); +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/ExceptionDaylightDao.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/ExceptionDaylightDao.java new file mode 100644 index 0000000..bea0ae6 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/ExceptionDaylightDao.java @@ -0,0 +1,33 @@ +package com.mgm.mcrm.basesetting.daylight.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import com.mgm.mcrm.basesetting.daylight.models.CfgExceptionDaylight; + +public interface ExceptionDaylightDao extends JpaRepository { + CfgExceptionDaylight findById(long id); + List findAll(Specification spec, Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + + @Transactional + @Modifying + @Query(value = " delete from cfg_exception_daylight where id=?1 ",nativeQuery=true) + int deleteById(long id); + + @Query(value="select * from cfg_exception_daylight where id =?1",nativeQuery=true) + CfgExceptionDaylight getById(long id); + + @Query(value="select count(1) from cfg_team_structure where user_id=?1 ", nativeQuery=true) + int countByKeys(String userId); + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/ExceptionDaylightViewDao.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/ExceptionDaylightViewDao.java new file mode 100644 index 0000000..6e08d16 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/ExceptionDaylightViewDao.java @@ -0,0 +1,29 @@ +package com.mgm.mcrm.basesetting.daylight.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; +import com.mgm.mcrm.basesetting.daylight.models.CfgExceptionDaylightView; + + +public interface ExceptionDaylightViewDao extends JpaRepository { + @EntityGraph(value = "graph.ExceptionDaylightMapping.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + CfgExceptionDaylightView findById(long id); + + @EntityGraph(value = "graph.ExceptionDaylightMapping.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findAll(Specification spec, Sort sort); + + @EntityGraph(value = "graph.ExceptionDaylightMapping.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findAll(Specification spec); + + Page findAll(Specification spec, Pageable pageable); + + @EntityGraph(value = "graph.ExceptionDaylightMapping.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findByUserIdLikeAndPropertyIdAndBookingTypeId(String userId, Long propertyId, Long bookingTypeId); + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/ExceptionOperaDao.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/ExceptionOperaDao.java new file mode 100644 index 0000000..5b24b6e --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/ExceptionOperaDao.java @@ -0,0 +1,35 @@ +package com.mgm.mcrm.basesetting.daylight.repositories; + +import com.mgm.mcrm.basesetting.daylight.models.CfgExceptionOperaView; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +public interface ExceptionOperaDao extends JpaRepository { + CfgExceptionOperaView findById(long id); + + List findAll(Specification spec, Sort sort); + + List findAll(Specification spec); + + Page findAll(Specification spec, Pageable pageable); + + @Transactional + @Modifying + @Query(value = " delete from cfg_opera where id=?1 ", nativeQuery = true) + int deleteById(long id); + + @Query(value = "select * from cfg_opera where id =?1", nativeQuery = true) + CfgExceptionOperaView getById(long id); + + @Query(value = "select count(1) from cfg_team_structure where user_id=?1 ", nativeQuery = true) + int countByKeys(String userId); + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/ExceptionOperaViewDao.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/ExceptionOperaViewDao.java new file mode 100644 index 0000000..efc195d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/ExceptionOperaViewDao.java @@ -0,0 +1,33 @@ +package com.mgm.mcrm.basesetting.daylight.repositories; + + +import com.mgm.mcrm.basesetting.daylight.models.CfgExceptionOperaView; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + + +public interface ExceptionOperaViewDao extends JpaRepository { + @EntityGraph(value = "graph.ExceptionOperaMapping.fulldetails", type = EntityGraph.EntityGraphType.LOAD) + CfgExceptionOperaView findById(long id); + + @EntityGraph(value = "graph.ExceptionOperaMapping.fulldetails", type = EntityGraph.EntityGraphType.LOAD) + List findAll(Specification spec, Sort sort); + + @EntityGraph(value = "graph.ExceptionOperaMapping.fulldetails", type = EntityGraph.EntityGraphType.LOAD) + List findAll(Specification spec); + + Page findAll(Specification spec, Pageable pageable); + + @EntityGraph(value = "graph.ExceptionOperaMapping.fulldetails", type = EntityGraph.EntityGraphType.LOAD) + List findByUserIdAndPropertyIdAndBookingTypeId(String userId, Long propertyId, Long bookingTypeId); + + @EntityGraph(value = "graph.ExceptionOperaMapping.fulldetails", type = EntityGraph.EntityGraphType.LOAD) + List findByUserIdLikeAndPropertyIdAndBookingTypeId(String userId, Long propertyId, Long bookingTypeId); + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/ItemInventoryDao.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/ItemInventoryDao.java new file mode 100644 index 0000000..5d00fb9 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/ItemInventoryDao.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.basesetting.daylight.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import com.mgm.mcrm.basesetting.daylight.models.CfgItemInventory; + +public interface ItemInventoryDao extends JpaRepository { + CfgItemInventory findByTierIdAndRoomId(Long tierId,Long roomId); + List findAll(Specification spec); + List findAll(Specification spec, Sort sort); + Page findAll(Specification spec, Pageable pageable); + + CfgItemInventory findByTierIdAndRoomIdAndPropertyId(Long tierId, Long roomId, Long propertyId); +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/MarketCodeDao.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/MarketCodeDao.java new file mode 100644 index 0000000..2443fce --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/MarketCodeDao.java @@ -0,0 +1,35 @@ +package com.mgm.mcrm.basesetting.daylight.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import com.mgm.mcrm.basesetting.daylight.models.CfgMarketCodes; + + +public interface MarketCodeDao extends JpaRepository { + CfgMarketCodes findById(long id); + List findByCode(String code); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + + @Transactional + @Modifying + @Query(value = " delete from cfg_market_codes where id=?1 ",nativeQuery=true) + int deleteById(long id); + + @Query(value="select * from cfg_market_codes where id =?1",nativeQuery=true) + CfgMarketCodes getById(long id); + + List findByCodeAndCategory(String code, String category); + + CfgMarketCodes findByDlMarketSegmentId(String dlMarketSegmentId); +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/OperaViewDao.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/OperaViewDao.java new file mode 100644 index 0000000..f038720 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/OperaViewDao.java @@ -0,0 +1,36 @@ +package com.mgm.mcrm.basesetting.daylight.repositories; + +import com.mgm.mcrm.basesetting.daylight.models.CfgDaylightView; +import com.mgm.mcrm.basesetting.daylight.models.CfgOperaView; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; +import java.util.Optional; + + +public interface OperaViewDao extends JpaRepository { + @EntityGraph(value = "graph.OperaMapping.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + CfgOperaView findById(long id); + + @EntityGraph(value = "graph.OperaMapping.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findAll(Specification spec, Sort sort); + + @EntityGraph(value = "graph.OperaMapping.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findAll(Specification spec); + + Page findAll(Specification spec, Pageable pageable); + + @EntityGraph(value = "graph.OperaMapping.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findBySectionIdAndPropertyIdAndBookingTypeId(Long sectionId, Long propertyId, Long bookingTypeId); + + @EntityGraph(value = "graph.OperaMapping.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findByMarketCodeIdAndRateCodeId(Long marketCodeId, Long rateCodeId); + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/OtherSegmentDao.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/OtherSegmentDao.java new file mode 100644 index 0000000..6cf09e6 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/OtherSegmentDao.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.basesetting.daylight.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; + +import com.mgm.mcrm.basesetting.daylight.models.CfgOtherSegment; + + +public interface OtherSegmentDao extends JpaRepository { + CfgOtherSegment findById(long id); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/RateCodeDao.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/RateCodeDao.java new file mode 100644 index 0000000..3f0e3f3 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/RateCodeDao.java @@ -0,0 +1,35 @@ +package com.mgm.mcrm.basesetting.daylight.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import com.mgm.mcrm.basesetting.daylight.models.CfgRateCodes; + + +public interface RateCodeDao extends JpaRepository { + CfgRateCodes findById(long id); + List findByCode(String code); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + + @Transactional + @Modifying + @Query(value = " delete from cfg_rate_codes where id=?1 ",nativeQuery=true) + int deleteById(long id); + + @Query(value="select * from cfg_rate_codes where id =?1",nativeQuery=true) + CfgRateCodes getById(long id); + + List findByCodeAndCategory(String ratePlanCode, String category); + + CfgRateCodes findByDlRatePlanId(String dlRatePlanId); +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/SourceCodeDao.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/SourceCodeDao.java new file mode 100644 index 0000000..e361d8d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/SourceCodeDao.java @@ -0,0 +1,32 @@ +package com.mgm.mcrm.basesetting.daylight.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import com.mgm.mcrm.basesetting.daylight.models.CfgRateCodes; +import com.mgm.mcrm.basesetting.daylight.models.CfgSourceCodes; + + +public interface SourceCodeDao extends JpaRepository { + CfgSourceCodes findById(long id); + CfgSourceCodes findByDlSourceId(String dlSourceId); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + + @Transactional + @Modifying + @Query(value = " delete from cfg_source_codes where id=?1 ",nativeQuery=true) + int deleteById(long id); + + @Query(value="select * from cfg_source_codes where id =?1",nativeQuery=true) + CfgSourceCodes getById(String loginId); +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/TierDao.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/TierDao.java new file mode 100644 index 0000000..1be8950 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/repositories/TierDao.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.basesetting.daylight.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import com.mgm.mcrm.basesetting.daylight.models.CfgTiers; + +public interface TierDao extends JpaRepository { + CfgTiers findByTierNameAndCategory(String string, String category); + List findAll(Specification spec); + List findAll(Specification spec, Sort sort); + Page findAll(Specification spec, Pageable pageable); + + CfgTiers findByDaylightTier(String daylightTier); +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/daylight/services/DaylightService.java b/src/main/java/com/mgm/mcrm/basesetting/daylight/services/DaylightService.java new file mode 100644 index 0000000..65d3645 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/daylight/services/DaylightService.java @@ -0,0 +1,2204 @@ +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.response.*; +import com.mgm.mcrm.basesetting.daylight.dtos.request.*; +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.enums.EnumBookingStatus; +import com.mgm.mcrm.common.dtos.HttpResult; +import com.mgm.mcrm.common.dtos.mgm_api.PlayerProfileEntry; +import com.mgm.mcrm.common.httpclient.HttpHeaderBuilder; +import com.mgm.mcrm.common.services.HttpService; +import com.mgm.mcrm.common.utils.*; +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; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class DaylightService { + + @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("${mcrm.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; + } + + if (operationData.getJSONArray("steps") == null) { + return null; + } + + JSONArray jsonArray = operationData.getJSONArray("steps"); + + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject jsonObject = jsonArray.getJSONObject(i); + + if ("UpsertReservations".equalsIgnoreCase(jsonObject.getString("name"))) { + + JSONObject propertiesJSON = jsonObject.getJSONObject("properties"); + JSONObject errorJSON = propertiesJSON.getJSONObject("error"); + + return errorJSON.getString("message"); + } + } + + return null; + } + + 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"); + + ReservationNoteResponse object = jsonArray.getObject(0, ReservationNoteResponse.class); + result.setData(object); + result.setSuccess(true); + } 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++; + } + } 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")); + 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/booking/v1/reservations?pageNumber=1&pageSize=50&filter=profileId==" + profileId + + ";(statusCode.code==DI,statusCode.code==RS,statusCode.code==DO,statusCode.code==IH,statusCode.code==CX)" +// + ";departureDate=ge=" + currentDate + + "&extend=PurchaseElements&extend=CustomFields&extend=Breakdown&extend=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.sslGetNoLog(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())); + + 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 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(); + + String needCompRulesId = null; + Long version = null; + for (int i = 0; i < compRuleList.size(); i++) { + JSONObject one = compRuleList.getJSONObject(i); + + JSONObject complimentaryRuleLimits = one.getJSONObject("complimentaryRuleLimits"); + JSONObject totalAmountLimit = complimentaryRuleLimits.getJSONObject("totalAmountLimit"); + + if (totalAmountLimit != null) { + needCompRulesId = one.getString("id"); + version = one.getLong("version"); + break; + } + } + + if (StringUtils.isEmpty(needCompRulesId)) { + result.setSuccess(false); + result.setMessage("Not found comp rule"); + return result; + } + + try { + 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(); + + ComplimentaryRuleLimits crl = getMiscChargeComplimentaryRuleLimits(startDate, endDate, miscCharge, daylightView.getSoftLimit()); + + updateCompRuleRequest.setComplimentaryRuleLimits(crl); + + BaseApiResponse updateResponse = updateCompRule(url, headers, updateCompRuleRequest); + + if (updateResponse.isSuccess()) { + result.setSuccess(true); + result.setMessage(updateResponse.getMessage()); + } else { + result.setSuccess(false); + result.setMessage(updateResponse.getMessage()); + } + } catch (Exception e) { + result.setSuccess(false); + result.setMessage(e.getMessage()); + LogUtil.error(DaylightService.class, e.getMessage()); + } + + 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(DaylightService.class, e.getMessage()); + return result; + } + } + + if (compRuleCount >= 2 || (!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(DaylightService.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(DaylightService.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(DaylightService.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(DaylightService.class, "Set block Success"); + } else { + serviceResult.setSuccess(false); + serviceResult.setMessage("Set block failed"); + serviceResult.setLogMessage(httpResult.getResult()); + + LogUtil.error(DaylightService.class, "Set block failure"); + } + } catch (Exception e) { + serviceResult.setSuccess(false); + serviceResult.setMessage("Set block failed"); + LogUtil.error(DaylightService.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(DaylightService.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(DaylightService.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(DaylightService.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()); + 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/basesetting/property/dtos/response/DayLightProfileResponse.java b/src/main/java/com/mgm/mcrm/basesetting/property/dtos/response/DayLightProfileResponse.java new file mode 100644 index 0000000..5a0cd81 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/property/dtos/response/DayLightProfileResponse.java @@ -0,0 +1,11 @@ +package com.mgm.mcrm.basesetting.property.dtos.response; + +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Data; + +import java.util.List; + +@Data +public class DayLightProfileResponse { + private String id; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/property/dtos/response/DescriptionResponse.java b/src/main/java/com/mgm/mcrm/basesetting/property/dtos/response/DescriptionResponse.java new file mode 100644 index 0000000..bd75663 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/property/dtos/response/DescriptionResponse.java @@ -0,0 +1,9 @@ +package com.mgm.mcrm.basesetting.property.dtos.response; + +import lombok.Data; + +@Data +public class DescriptionResponse { + private String languageCode; + private String content; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/property/dtos/response/ResultResponse.java b/src/main/java/com/mgm/mcrm/basesetting/property/dtos/response/ResultResponse.java new file mode 100644 index 0000000..eb2cb59 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/property/dtos/response/ResultResponse.java @@ -0,0 +1,36 @@ +package com.mgm.mcrm.basesetting.property.dtos.response; + +import com.mgm.mcrm.basesetting.daylight.dtos.response.ProfileDetailResponse; +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Data; + +import java.util.List; + +/** + * 对应外层返回的 JSON: + * { + * \"results\": { \"PropertyType\": [ ... ] }, + * \"paging\": { ... } + * } + */ +@Data +public class ResultResponse { + + /** + * 对应 JSON 中的 results 对象 + */ + private Object results; + + /** + * 对应 JSON 中的 paging 对象 + */ + private PagingResponse paging; + + + @Data + public static class PagingResponse { + private Integer pageNumber; + private Integer pageSize; + private Integer totalCount; + } +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/property/dtos/response/TokenResponse.java b/src/main/java/com/mgm/mcrm/basesetting/property/dtos/response/TokenResponse.java new file mode 100644 index 0000000..f529739 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/property/dtos/response/TokenResponse.java @@ -0,0 +1,12 @@ +package com.mgm.mcrm.basesetting.property.dtos.response; + +import lombok.Data; + +@Data +public class TokenResponse { + private String access_token; + private String expires_in; + private String token_type; + private String refresh_token; + private String scope; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/property/models/CfgBlocks.java b/src/main/java/com/mgm/mcrm/basesetting/property/models/CfgBlocks.java new file mode 100644 index 0000000..0f3c475 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/property/models/CfgBlocks.java @@ -0,0 +1,112 @@ +package com.mgm.mcrm.basesetting.property.models; + +import java.io.Serializable; +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.Transient; + +@Entity +@Table(name="cfg_blocks") +public class CfgBlocks implements Serializable { + //fields in table + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="name") + private String name; + @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; + + @Transient + private Integer appChannel; + @Transient + private Integer available; + @Transient + private Integer pickedUp; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + public Integer getAppChannel() { + return appChannel; + } + + public void setAppChannel(Integer appChannel) { + this.appChannel = appChannel; + } + + public Integer getAvailable() { + return available; + } + + public void setAvailable(Integer available) { + this.available = available; + } + + public Integer getPickedUp() { + return pickedUp; + } + + public void setPickedUp(Integer pickedUp) { + this.pickedUp = pickedUp; + } + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/property/models/CfgProperties.java b/src/main/java/com/mgm/mcrm/basesetting/property/models/CfgProperties.java new file mode 100644 index 0000000..cc72821 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/property/models/CfgProperties.java @@ -0,0 +1,47 @@ +package com.mgm.mcrm.basesetting.property.models; + +import java.io.Serializable; +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 lombok.Data; + +@Data +@Entity +@Table(name="cfg_properties") +public class CfgProperties implements Serializable { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="name") + private String name; + @Column(name="code") + private String code; + @Column(name="name_zht") + private String nameZht; + @Column(name="name_zhs") + private String nameZhs; + @Column(name="category") + private String category; + @Column(name="hotel_code") + private String hotelCode; + @Column(name="dl_property_id") + private String dlPropertyId; + @Column(name="sort_order") + private Integer sortOrder; + + @Column(name="created_at") + private Date createdAt; + @Column(name="updated_at") + private Date updatedAt; + + @Column(name = "status") + private int status; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/property/repositories/BlockDao.java b/src/main/java/com/mgm/mcrm/basesetting/property/repositories/BlockDao.java new file mode 100644 index 0000000..da686b8 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/property/repositories/BlockDao.java @@ -0,0 +1,35 @@ +package com.mgm.mcrm.basesetting.property.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import com.mgm.mcrm.basesetting.property.models.CfgBlocks; + + + +public interface BlockDao extends JpaRepository { + CfgBlocks findById(long id); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + + @Transactional + @Modifying + @Query(value = " delete from cfg_blocks where id=?1 ",nativeQuery=true) + int deleteById(long id); + + + @Query(value="select * from cfg_blocks where id =?1",nativeQuery=true) + CfgBlocks getById(Integer id); + + @Query(value="select * from cfg_blocks where name =?1",nativeQuery=true) + CfgBlocks getByName(String name); +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/property/repositories/PropertyDao.java b/src/main/java/com/mgm/mcrm/basesetting/property/repositories/PropertyDao.java new file mode 100644 index 0000000..6ae3df5 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/property/repositories/PropertyDao.java @@ -0,0 +1,54 @@ +package com.mgm.mcrm.basesetting.property.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import com.mgm.mcrm.basesetting.property.models.CfgProperties; + +public interface PropertyDao extends JpaRepository { + @Query(value="select * from cfg_properties with (nolock) where id=?1",nativeQuery=true) + CfgProperties getById(long id); + + @Query(value="select * from cfg_properties with (nolock) where name=?1",nativeQuery=true) + CfgProperties getByName(String name); + + @Query(value="select * from cfg_properties with (nolock) where hotel_code=?1",nativeQuery=true) + CfgProperties getByHotelCode(String hotelCode); + + @Query(value="select * from cfg_properties with (nolock) where code=?1",nativeQuery=true) + CfgProperties getByCode(String code); + + @Query(value="select * from cfg_properties with (nolock) where hotel_code=?1",nativeQuery=true) + CfgProperties findByHotelCode(String hotelCode); + + @Query(value="select * from cfg_properties with (nolock) where dl_property_id=?1",nativeQuery=true) + CfgProperties getByDlPropertyId(String propertyId); + + @Query(value="select Top(1) * from cfg_properties with (nolock) where name like %?1%",nativeQuery=true) + CfgProperties getByLikeName(String name); + + @Query(value="select * from cfg_properties with (nolock) where name=?1 and category = 'DAYLIGHT'",nativeQuery=true) + CfgProperties getByPropertyNameDaylight(String propertyId); + + List findAll(Specification spec); + List findAll(Specification spec, Sort sort); + Page findAll(Specification spec, Pageable pageable); + + @Transactional + @Modifying + @Query(value = " delete from cfg_properties where id=?1 ",nativeQuery=true)//ok + int deleteById(long id); + + @Query(value="select top(1) * from cfg_properties with (nolock) where upper(name)=upper(?1) ",nativeQuery=true) + CfgProperties queryByName(String propertyName); + + List findByCategory(String category); +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/property/services/PropertyCache.java b/src/main/java/com/mgm/mcrm/basesetting/property/services/PropertyCache.java new file mode 100644 index 0000000..aab9da3 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/property/services/PropertyCache.java @@ -0,0 +1,31 @@ +package com.mgm.mcrm.basesetting.property.services; + +import com.mgm.mcrm.basesetting.property.models.CfgProperties; +import com.mgm.mcrm.basesetting.property.repositories.PropertyDao; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class PropertyCache { + + @Resource + private PropertyDao propertyDao; + + private volatile List propertiesList; + + @PostConstruct + public void init() { + refresh(); + } + + public List getProperties() { + return propertiesList; + } + + public void refresh() { + propertiesList = propertyDao.findByCategory("DAYLIGHT"); + } +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgBedTypeMapping.java b/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgBedTypeMapping.java new file mode 100644 index 0000000..9061760 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgBedTypeMapping.java @@ -0,0 +1,46 @@ +package com.mgm.mcrm.basesetting.room.models; + +import java.util.Date; +import java.util.List; + +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.Transient; +import lombok.Data; + +@Data +@Entity +@Table(name="cfg_bed_type_mapping") +public class CfgBedTypeMapping { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + @Column(name = "bed_type_name") + private String bedTypeName; + @Column(name = "property_id") + private Integer propertyId; + @Column(name = "room_id") + private Integer roomId; + @Column(name = "room_type_id") + private Integer roomTypeId; + @Column(name = "master_group_id") + private Integer masterGroupId; + @Column(name="created_at") + private Date createdAt; + @Column(name="updated_at") + private Date updatedAt; + @Column(name="created_by") + private String createdBy; + @Column(name="updated_by") + private String updatedBy; + + @Transient + private List selectRoomTypeIds; + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgBedTypeMappingView.java b/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgBedTypeMappingView.java new file mode 100644 index 0000000..b90b2d1 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgBedTypeMappingView.java @@ -0,0 +1,104 @@ +package com.mgm.mcrm.basesetting.room.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; + +@Entity +@Table(name="cfg_bed_type_mapping") +public class CfgBedTypeMappingView { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + @Column(name = "bed_type_name") + private String bedTypeName; + @Column(name = "property_id") + private Integer propertyId; + @Column(name = "room_id") + private Integer roomId; + @Column(name = "room_type_id") + private Integer roomTypeId; + @Column(name = "master_group_id") + private Integer masterGroupId; + @Column(name="created_at") + private Date createdAt; + @Column(name="updated_at") + private Date updatedAt; + @Column(name="created_by") + private String createdBy; + @Column(name="updated_by") + private String updatedBy; + +// @NotFound(action = NotFoundAction.IGNORE) +// @OneToMany(fetch = FetchType.EAGER) +// @JoinTable(name="cfg_bed_type_mapping",joinColumns={@JoinColumn(name="room_id")},inverseJoinColumns={@JoinColumn(name="room_type_id")}) +// private List roomRoomType ; + + public Integer getId() { + return id; + } + public void setId(Integer id) { + this.id = id; + } + public String getBedTypeName() { + return bedTypeName; + } + public void setBedTypeName(String bedTypeName) { + this.bedTypeName = bedTypeName; + } + public Integer getPropertyId() { + return propertyId; + } + public void setPropertyId(Integer propertyId) { + this.propertyId = propertyId; + } + public Integer getRoomId() { + return roomId; + } + public void setRoomId(Integer roomId) { + this.roomId = roomId; + } + public Integer getRoomTypeId() { + return roomTypeId; + } + public void setRoomTypeId(Integer roomTypeId) { + this.roomTypeId = roomTypeId; + } + public Integer getMasterGroupId() { + return masterGroupId; + } + public void setMasterGroupId(Integer masterGroupId) { + this.masterGroupId = masterGroupId; + } + public Date getCreatedAt() { + return createdAt; + } + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + public Date getUpdatedAt() { + return updatedAt; + } + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + public String getCreatedBy() { + return createdBy; + } + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + public String getUpdatedBy() { + return updatedBy; + } + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgOtherRoomStatus.java b/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgOtherRoomStatus.java new file mode 100644 index 0000000..1ebee80 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgOtherRoomStatus.java @@ -0,0 +1,100 @@ +package com.mgm.mcrm.basesetting.room.models; + +import java.io.Serializable; +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; + +@Entity +@Table(name="cfg_other_room_status") +public class CfgOtherRoomStatus implements Serializable { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="room_status") + private String statusName; + @Column(name="is_pick_up") + private Integer pickup; + @Column(name="is_show_book") + private Integer showBooking; + @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; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + public Integer getPickup() { + return pickup; + } + + public void setPickup(Integer pickup) { + this.pickup = pickup; + } + + public Integer getShowBooking() { + return showBooking; + } + + public void setShowBooking(Integer showBooking) { + this.showBooking = showBooking; + } + + public String getStatusName() { + return statusName; + } + + public void setStatusName(String statusName) { + this.statusName = statusName; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgRoomFeatures.java b/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgRoomFeatures.java new file mode 100644 index 0000000..5a33bab --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgRoomFeatures.java @@ -0,0 +1,41 @@ +package com.mgm.mcrm.basesetting.room.models; + +import java.io.Serializable; +import java.time.LocalDateTime; + +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 lombok.Data; + +@Entity +@Table(name = "cfg_room_features") +@Data +public class CfgRoomFeatures implements Serializable { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + @Column(name = "description") + private String description; + @Column(name = "dl_attribute_id") + private String dlAttributeId; + @Column(name = "created_at") + private LocalDateTime createdAt; + @Column(name = "created_by") + private String createdBy; + @Column(name = "updated_at") + private LocalDateTime updatedAt; + @Column(name = "updated_by") + private String updatedBy; + @Column(name = "code") + private String code; + @Column(name = "is_show") + private Integer showInBooking; + @Column(name = "category") + private String category; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgRoomTypes.java b/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgRoomTypes.java new file mode 100644 index 0000000..63ce3bd --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgRoomTypes.java @@ -0,0 +1,39 @@ +package com.mgm.mcrm.basesetting.room.models; + +import java.io.Serializable; +import java.time.LocalDateTime; + +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 lombok.Data; + +@Entity +@Table(name="cfg_room_types") +@Data +public class CfgRoomTypes implements Serializable { + //fields in table + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="code") + private String code; + @Column(name="name_cn") + private String nameCN; + @Column(name="created_at") + private LocalDateTime createdAt; + @Column(name="created_by") + private String createdBy; + @Column(name="updated_at") + private LocalDateTime updatedAt; + @Column(name="updated_by") + private String updatedBy; + @Column(name = "dl_room_type_id") + private String dlRoomTypeId; + @Column(name = "category") + private String category; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgRooms.java b/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgRooms.java new file mode 100644 index 0000000..e336663 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgRooms.java @@ -0,0 +1,67 @@ +package com.mgm.mcrm.basesetting.room.models; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +import jakarta.persistence.*; + +import lombok.Data; +import org.hibernate.annotations.NotFound; +import org.hibernate.annotations.NotFoundAction; +import com.mgm.mcrm.basesetting.property.models.CfgProperties; + +@Data +@Entity +@Table(name="cfg_rooms") +@NamedEntityGraph( + name = "graph.RoomSetting.fulldetails", + attributeNodes = { + @NamedAttributeNode("roomRoomType"), + @NamedAttributeNode("propertyObj") + } +) +public class CfgRooms implements Serializable { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="name") + private String name; + @Column(name="name_cn") + private String nameCN; + @Column(name="property_id") + private String propertyId; + @Column(name="sharer_limit") + private Integer sharerLimit; + @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="room_category") + private String roomCategory; + @Column(name="for_booking") + private Integer forBooking; + @Column(name="for_waitlist") + private Integer forWaitlist; + + @Column(name = "category") + private String category; + + @Transient + private List roomTypeIds; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name="cfg_rooms_room_types",joinColumns={@JoinColumn(name="room_id")},inverseJoinColumns={@JoinColumn(name="room_type_id")}) + private List roomRoomType ; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="property_id",insertable=false ,updatable=false) + private CfgProperties propertyObj; +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgRoomsRoomTypes.java b/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgRoomsRoomTypes.java new file mode 100644 index 0000000..c624a55 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgRoomsRoomTypes.java @@ -0,0 +1,53 @@ +package com.mgm.mcrm.basesetting.room.models; + +import java.io.Serializable; +import java.util.Date; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.Table; + +@Entity +@Table(name="cfg_rooms_room_types") +@IdClass(CfgRoomsRoomTypesKey.class) +public class CfgRoomsRoomTypes implements Serializable { + //fields in table + @Id + @Column(name="room_id") + private Long roomId; + @Id + @Column(name="room_type_id") + private Long roomTypeId; + @Column(name="created_at") + private Date createdAt; + @Column(name="created_by") + private String createdBy; + public Long getRoomId() { + return roomId; + } + public void setRoomId(Long roomId) { + this.roomId = roomId; + } + public Long getRoomTypeId() { + return roomTypeId; + } + public void setRoomTypeId(Long roomTypeId) { + this.roomTypeId = roomTypeId; + } + public Date getCreatedAt() { + return createdAt; + } + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + public String getCreatedBy() { + return createdBy; + } + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgRoomsRoomTypesKey.java b/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgRoomsRoomTypesKey.java new file mode 100644 index 0000000..4cfdf53 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/room/models/CfgRoomsRoomTypesKey.java @@ -0,0 +1,46 @@ +package com.mgm.mcrm.basesetting.room.models; + +import java.io.Serializable; + +public class CfgRoomsRoomTypesKey implements Serializable{ + + private static final long serialVersionUID = 6060166117433738173L; + private Long roomId; + private Long roomTypeId; + + public Long getRoomId() { + return roomId; + } + + public void setRoomId(Long roomId) { + this.roomId = roomId; + } + + public Long getRoomTypeId() { + return roomTypeId; + } + + public void setRoomTypeId(Long roomTypeId) { + this.roomTypeId = roomTypeId; + } + + @Override + public boolean equals(Object o) { + if(o instanceof CfgRoomsRoomTypesKey) + { + CfgRoomsRoomTypesKey key = (CfgRoomsRoomTypesKey)o ; + if(this.roomId == key.getRoomId() && + this.roomTypeId == key.getRoomTypeId()) + { + return true ; + } + } + return false ; + } + + @Override + public int hashCode() { + return 1; + } + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/room/repositories/BedTypeMappingDao.java b/src/main/java/com/mgm/mcrm/basesetting/room/repositories/BedTypeMappingDao.java new file mode 100644 index 0000000..eaad6ac --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/room/repositories/BedTypeMappingDao.java @@ -0,0 +1,34 @@ +package com.mgm.mcrm.basesetting.room.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import com.mgm.mcrm.basesetting.room.models.CfgBedTypeMapping; + +public interface BedTypeMappingDao extends JpaRepository { + + List findAll(Specification spec); + List findAll(Specification spec, Sort sort); + Page findAll(Specification spec, Pageable pageable); + + + public interface BedType { + Long getPropertyId(); + Long getRoomId(); + String getBedTypeName(); + Long getMasterGroupId(); + } + + @Query(value="select distinct property_id as propertyId,room_id as roomId,bed_type_name as bedTypeName,master_group_id as masterGroupId from cfg_bed_type_mapping where property_id =?1 and room_id=?2",nativeQuery=true) + List queryByPropertyIdAndRoomId(Long propertyId,Long roomId); + + @Query(value="select * from cfg_bed_type_mapping where master_group_id =?1",nativeQuery=true) + List queryByMasterGroupId(Long masterGroupId); + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/room/repositories/OtherRoomStatusDao.java b/src/main/java/com/mgm/mcrm/basesetting/room/repositories/OtherRoomStatusDao.java new file mode 100644 index 0000000..d0a327c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/room/repositories/OtherRoomStatusDao.java @@ -0,0 +1,32 @@ +package com.mgm.mcrm.basesetting.room.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import com.mgm.mcrm.basesetting.room.models.CfgOtherRoomStatus; + + +public interface OtherRoomStatusDao extends JpaRepository { + CfgOtherRoomStatus findById(long id); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + + CfgOtherRoomStatus findByStatusName(String statusName); + + @Query(value="select id from cfg_other_room_status where is_pick_up = 1",nativeQuery=true) + Long[] findIsPickUpId(); + + @Query(value="SELECT id FROM cfg_other_room_status where room_status = 'Pending'",nativeQuery=true) + Long getPendingId(); + + @Query(value="SELECT id FROM cfg_other_room_status where room_status = 'Cancel'",nativeQuery=true) + Long getCancelId(); + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/room/repositories/RoomDao.java b/src/main/java/com/mgm/mcrm/basesetting/room/repositories/RoomDao.java new file mode 100644 index 0000000..1bc9eab --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/room/repositories/RoomDao.java @@ -0,0 +1,37 @@ +package com.mgm.mcrm.basesetting.room.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import com.mgm.mcrm.basesetting.room.models.CfgRooms; + +public interface RoomDao extends JpaRepository { + + @EntityGraph(value = "graph.RoomSetting.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + CfgRooms findById(long id); + + @EntityGraph(value = "graph.RoomSetting.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findAll(Specification spec,Sort sort); + + @EntityGraph(value = "graph.RoomSetting.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findAll(Specification spec); + + Page findAll(Specification spec, Pageable pageable); + + @Transactional + @Modifying + @Query(value = " delete from cfg_rooms where id=?1 ",nativeQuery=true) + int deleteById(long id); + + @Query(value="select * from cfg_rooms where id =?1",nativeQuery=true) + CfgRooms getById(Long id); +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/room/repositories/RoomFeatureDao.java b/src/main/java/com/mgm/mcrm/basesetting/room/repositories/RoomFeatureDao.java new file mode 100644 index 0000000..d4db43d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/room/repositories/RoomFeatureDao.java @@ -0,0 +1,30 @@ +package com.mgm.mcrm.basesetting.room.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import com.mgm.mcrm.basesetting.room.models.CfgRoomFeatures; + +public interface RoomFeatureDao extends JpaRepository { + List findAll(Specification spec); + List findAll(Specification spec, Sort sort); + Page findAll(Specification spec, Pageable pageable); + void deleteById(Integer id); + + @Query(value="select * from cfg_room_features where code =?1 and category='OPERA'",nativeQuery=true) + CfgRoomFeatures getByOperaCode(String code); + + @Query(value="select * from cfg_room_features where code =?1 and category='DAYLIGHT'",nativeQuery=true) + CfgRoomFeatures getByDaylightCode(String code); + + @Query(value="select * from cfg_room_features where description =?1",nativeQuery=true) + CfgRoomFeatures getByDescription(String desc); + + CfgRoomFeatures findByCodeAndCategory(String code, String category); +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/room/repositories/RoomRoomTypeDao.java b/src/main/java/com/mgm/mcrm/basesetting/room/repositories/RoomRoomTypeDao.java new file mode 100644 index 0000000..6d8b690 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/room/repositories/RoomRoomTypeDao.java @@ -0,0 +1,16 @@ +package com.mgm.mcrm.basesetting.room.repositories; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import com.mgm.mcrm.basesetting.room.models.CfgRoomsRoomTypes; + + +public interface RoomRoomTypeDao extends JpaRepository { + List findByRoomTypeId(Long roomTypeId); + + @Query(value="select * from cfg_rooms_room_types where room_id =?1",nativeQuery=true) + List queryByRoomId(Long roomId); +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/room/repositories/RoomTypeDao.java b/src/main/java/com/mgm/mcrm/basesetting/room/repositories/RoomTypeDao.java new file mode 100644 index 0000000..d96069c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/room/repositories/RoomTypeDao.java @@ -0,0 +1,33 @@ +package com.mgm.mcrm.basesetting.room.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import com.mgm.mcrm.basesetting.room.models.CfgRoomTypes; + + +public interface RoomTypeDao extends JpaRepository { + CfgRoomTypes findById(long id); + CfgRoomTypes findByCodeAndCategory(String code,String category); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + + @Transactional + @Modifying + @Query(value = " delete from cfg_room_types where id=?1 ",nativeQuery=true) + int deleteById(long id); + + @Query(value="select * from cfg_room_types where id =?1",nativeQuery=true) + CfgRoomTypes getById(Long id); + + CfgRoomTypes findByDlRoomTypeId(String dlRoomTypeId); +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/room/services/OtherRoomStatusService.java b/src/main/java/com/mgm/mcrm/basesetting/room/services/OtherRoomStatusService.java new file mode 100644 index 0000000..0fb75f0 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/room/services/OtherRoomStatusService.java @@ -0,0 +1,20 @@ +package com.mgm.mcrm.basesetting.room.services; + +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import com.mgm.mcrm.basesetting.room.models.CfgOtherRoomStatus; +import com.mgm.mcrm.basesetting.room.repositories.OtherRoomStatusDao; + +@Service +public class OtherRoomStatusService { + + @Resource + private OtherRoomStatusDao otherRoomStatusDao; + + public CfgOtherRoomStatus getOtherRoomStatusById(long id) { + CfgOtherRoomStatus roomStatus = otherRoomStatusDao.findById(id); + return roomStatus; + } + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/team/models/AppUsers.java b/src/main/java/com/mgm/mcrm/basesetting/team/models/AppUsers.java new file mode 100644 index 0000000..69e43b2 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/team/models/AppUsers.java @@ -0,0 +1,144 @@ +package com.mgm.mcrm.basesetting.team.models; + +import java.io.Serializable; +import java.util.Date; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; + +import org.hibernate.annotations.NotFound; +import org.hibernate.annotations.NotFoundAction; +import com.mgm.mcrm.basesetting.property.models.CfgProperties; + +@Entity +@Table(name="app_users") +public class AppUsers implements Serializable { + //fields in table + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="user_id") + private String userId; + @Column(name="team_id") + private Long teamId; + @Column(name="property_id") + private Long propertyId; + @Column(name="authorizer") + private String authorizer; + @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; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="team_id",insertable=false ,updatable=false) + private CfgDepartments userTeam; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="property_id",insertable=false ,updatable=false) + private CfgProperties userProperty; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Long getTeamId() { + return teamId; + } + + public void setTeamId(Long teamId) { + this.teamId = teamId; + } + + public Long getPropertyId() { + return propertyId; + } + + public void setPropertyId(Long propertyId) { + this.propertyId = propertyId; + } + + public String getAuthorizer() { + return authorizer; + } + + public void setAuthorizer(String authorizer) { + this.authorizer = authorizer; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + public CfgDepartments getUserTeam() { + return userTeam; + } + + public void setUserTeam(CfgDepartments userTeam) { + this.userTeam = userTeam; + } + + public CfgProperties getUserProperty() { + return userProperty; + } + + public void setUserProperty(CfgProperties userProperty) { + this.userProperty = userProperty; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/team/models/CfgDepartments.java b/src/main/java/com/mgm/mcrm/basesetting/team/models/CfgDepartments.java new file mode 100644 index 0000000..f6e4c35 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/team/models/CfgDepartments.java @@ -0,0 +1,68 @@ +package com.mgm.mcrm.basesetting.team.models; + +import java.io.Serializable; +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; + +@Entity +@Table(name="cfg_departments") +public class CfgDepartments implements Serializable { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="name") + private String name; + @Column(name="created_at") + private Date createdAt; + @Column(name="updated_at") + private Date updatedAt; + @Column(name="created_by") + private String createdBy; + @Column(name="updated_by") + private String updatedBy; + + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public Date getCreatedAt() { + return createdAt; + } + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + public Date getUpdatedAt() { + return updatedAt; + } + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + public String getCreatedBy() { + return createdBy; + } + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + public String getUpdatedBy() { + return updatedBy; + } + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/team/models/CfgDivisions.java b/src/main/java/com/mgm/mcrm/basesetting/team/models/CfgDivisions.java new file mode 100644 index 0000000..5484957 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/team/models/CfgDivisions.java @@ -0,0 +1,79 @@ +package com.mgm.mcrm.basesetting.team.models; + +import java.io.Serializable; +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; + +@Entity +@Table(name="cfg_divisions") +public class CfgDivisions implements Serializable { + //fields in table + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="name") + private String name; + @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; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/team/models/CfgOtherUserMapping.java b/src/main/java/com/mgm/mcrm/basesetting/team/models/CfgOtherUserMapping.java new file mode 100644 index 0000000..f6434d9 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/team/models/CfgOtherUserMapping.java @@ -0,0 +1,125 @@ +package com.mgm.mcrm.basesetting.team.models; + +import java.io.Serializable; +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; + +@Entity +@Table(name="cfg_other_user_mapping") +public class CfgOtherUserMapping implements Serializable { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="division_id") + private Long divisionId; + @Column(name="department_id") + private Long departmentId; + @Column(name="section_id") + private Long sectionId; + @Column(name="team_id") + private Long teamId; + @Column(name="property_id") + private Long propertyId; + @Column(name="booking_type_id") + private Long bookingTypeId; + @Column(name="market_code_id") + private Long marketCodeId; + @Column(name="segment_id") + private Long segmentId; + @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; + + public Date getCreatedAt() { + return createdAt; + } + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + public Date getUpdatedAt() { + return updatedAt; + } + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + public String getCreatedBy() { + return createdBy; + } + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + public String getUpdatedBy() { + return updatedBy; + } + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public Long getDivisionId() { + return divisionId; + } + public void setDivisionId(Long divisionId) { + this.divisionId = divisionId; + } + public Long getDepartmentId() { + return departmentId; + } + public void setDepartmentId(Long departmentId) { + this.departmentId = departmentId; + } + public Long getSectionId() { + return sectionId; + } + public void setSectionId(Long sectionId) { + this.sectionId = sectionId; + } + public Long getTeamId() { + return teamId; + } + public void setTeamId(Long teamId) { + this.teamId = teamId; + } + public Long getPropertyId() { + return propertyId; + } + public void setPropertyId(Long propertyId) { + this.propertyId = propertyId; + } + public Long getBookingTypeId() { + return bookingTypeId; + } + public void setBookingTypeId(Long bookingTypeId) { + this.bookingTypeId = bookingTypeId; + } + public Long getMarketCodeId() { + return marketCodeId; + } + public void setMarketCodeId(Long marketCodeId) { + this.marketCodeId = marketCodeId; + } + public Long getSegmentId() { + return segmentId; + } + public void setSegmentId(Long segmentId) { + this.segmentId = segmentId; + } + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/team/models/CfgSections.java b/src/main/java/com/mgm/mcrm/basesetting/team/models/CfgSections.java new file mode 100644 index 0000000..2bbaa4b --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/team/models/CfgSections.java @@ -0,0 +1,68 @@ +package com.mgm.mcrm.basesetting.team.models; + +import java.io.Serializable; +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; + +@Entity +@Table(name="cfg_sections") +public class CfgSections implements Serializable { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="name") + private String name; + @Column(name="created_at") + private Date createdAt; + @Column(name="updated_at") + private Date updatedAt; + @Column(name="created_by") + private String createdBy; + @Column(name="updated_by") + private String updatedBy; + + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public Date getCreatedAt() { + return createdAt; + } + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + public Date getUpdatedAt() { + return updatedAt; + } + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + public String getCreatedBy() { + return createdBy; + } + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + public String getUpdatedBy() { + return updatedBy; + } + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/team/models/CfgTeamStructure.java b/src/main/java/com/mgm/mcrm/basesetting/team/models/CfgTeamStructure.java new file mode 100644 index 0000000..810beb7 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/team/models/CfgTeamStructure.java @@ -0,0 +1,85 @@ +package com.mgm.mcrm.basesetting.team.models; + +import java.io.Serializable; +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; + +@Entity +@Table(name="cfg_team_structure") +public class CfgTeamStructure implements Serializable { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="division_id") + private Long divisionId; + @Column(name="department_id") + private Long departmentId; + @Column(name="section_id") + private Long sectionId; + @Column(name="created_at") + private Date createdAt; + @Column(name="updated_at") + private Date updatedAt; + @Column(name="created_by") + private String createdBy; + @Column(name="updated_by") + private String updatedBy; + + public Date getCreatedAt() { + return createdAt; + } + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + public Date getUpdatedAt() { + return updatedAt; + } + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + public String getCreatedBy() { + return createdBy; + } + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + public String getUpdatedBy() { + return updatedBy; + } + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public Long getDivisionId() { + return divisionId; + } + public void setDivisionId(Long divisionId) { + this.divisionId = divisionId; + } + public Long getDepartmentId() { + return departmentId; + } + public void setDepartmentId(Long departmentId) { + this.departmentId = departmentId; + } + public Long getSectionId() { + return sectionId; + } + public void setSectionId(Long sectionId) { + this.sectionId = sectionId; + } + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/team/models/CfgTeamStructureView.java b/src/main/java/com/mgm/mcrm/basesetting/team/models/CfgTeamStructureView.java new file mode 100644 index 0000000..f5f0461 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/team/models/CfgTeamStructureView.java @@ -0,0 +1,121 @@ +package com.mgm.mcrm.basesetting.team.models; + +import java.io.Serializable; +import java.util.Date; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedAttributeNode; +import jakarta.persistence.NamedEntityGraph; +import jakarta.persistence.NamedEntityGraphs; +import jakarta.persistence.Table; + +import org.hibernate.annotations.NotFound; +import org.hibernate.annotations.NotFoundAction; + +@Entity +@Table(name="cfg_team_structure") +@NamedEntityGraphs({ + @NamedEntityGraph( + name = "graph.TeamStructure.fulldetails", + attributeNodes = { + @NamedAttributeNode("divisionObj"), + @NamedAttributeNode("departmentObj"), + @NamedAttributeNode("sectionObj") + } + ) +}) +public class CfgTeamStructureView implements Serializable { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="division_id") + private Long divisionId; + @Column(name="department_id") + private Long departmentId; + @Column(name="section_id") + private Long sectionId; + @Column(name="created_at") + private Date createdAt; + @Column(name="updated_at") + private Date updatedAt; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="division_id",insertable=false ,updatable=false) + private CfgDivisions divisionObj; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="department_id",insertable=false ,updatable=false) + private CfgDepartments departmentObj; + + @NotFound(action = NotFoundAction.IGNORE) + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name="section_id",insertable=false ,updatable=false) + private CfgSections sectionObj; + + public Date getCreatedAt() { + return createdAt; + } + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + public Date getUpdatedAt() { + return updatedAt; + } + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public Long getDivisionId() { + return divisionId; + } + public void setDivisionId(Long divisionId) { + this.divisionId = divisionId; + } + public Long getDepartmentId() { + return departmentId; + } + public void setDepartmentId(Long departmentId) { + this.departmentId = departmentId; + } + public Long getSectionId() { + return sectionId; + } + public void setSectionId(Long sectionId) { + this.sectionId = sectionId; + } + public CfgDivisions getDivisionObj() { + return divisionObj; + } + public void setDivisionObj(CfgDivisions divisionObj) { + this.divisionObj = divisionObj; + } + public CfgDepartments getDepartmentObj() { + return departmentObj; + } + public void setDepartmentObj(CfgDepartments departmentObj) { + this.departmentObj = departmentObj; + } + public CfgSections getSectionObj() { + return sectionObj; + } + public void setSectionObj(CfgSections sectionObj) { + this.sectionObj = sectionObj; + } + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/team/repositories/AppUserDao.java b/src/main/java/com/mgm/mcrm/basesetting/team/repositories/AppUserDao.java new file mode 100644 index 0000000..2b30101 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/team/repositories/AppUserDao.java @@ -0,0 +1,30 @@ +package com.mgm.mcrm.basesetting.team.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import com.mgm.mcrm.basesetting.team.models.AppUsers; + + +public interface AppUserDao extends JpaRepository { + AppUsers findById(long id); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + + @Transactional + @Modifying + @Query(value = " delete from app_users where id=?1 ",nativeQuery=true) + int deleteById(long id); + + @Query(value="select * from app_users where id =?1",nativeQuery=true) + AppUsers getById(long id); +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/team/repositories/DepartmentDao.java b/src/main/java/com/mgm/mcrm/basesetting/team/repositories/DepartmentDao.java new file mode 100644 index 0000000..e3b94d8 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/team/repositories/DepartmentDao.java @@ -0,0 +1,34 @@ +package com.mgm.mcrm.basesetting.team.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import com.mgm.mcrm.basesetting.team.models.CfgDepartments; + + +public interface DepartmentDao extends JpaRepository { + @Query(value = "select * from cfg_departments with (nolock) where id=?1", nativeQuery = true) + CfgDepartments getById(long id); + + @Query(value = "select * from cfg_departments with (nolock) where name=?1", nativeQuery = true) + CfgDepartments getByName(String name); + + List findAll(Specification checkDuplicateSpec); + List findAll(Specification spec, Sort sort); + Page findAll(Specification spec, Pageable pageable); + + @Transactional + @Modifying + void deleteById(long id); + + + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/team/repositories/DivisionDao.java b/src/main/java/com/mgm/mcrm/basesetting/team/repositories/DivisionDao.java new file mode 100644 index 0000000..22b7040 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/team/repositories/DivisionDao.java @@ -0,0 +1,34 @@ +package com.mgm.mcrm.basesetting.team.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import com.mgm.mcrm.basesetting.team.models.CfgDivisions; + +public interface DivisionDao extends JpaRepository { + CfgDivisions findById(long id); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + + @Transactional + @Modifying + @Query(value = " delete from cfg_divisions where id=?1 ",nativeQuery=true) + int deleteById(long id); + + @Query(value="select * from cfg_divisions where id =?1",nativeQuery=true) + CfgDivisions getById(long id); + + @Query(value="select * from cfg_divisions where name =?1",nativeQuery=true) + CfgDivisions getByName(String name); + + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/team/repositories/OtherUserMappingDao.java b/src/main/java/com/mgm/mcrm/basesetting/team/repositories/OtherUserMappingDao.java new file mode 100644 index 0000000..046ebea --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/team/repositories/OtherUserMappingDao.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.basesetting.team.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; + +import com.mgm.mcrm.basesetting.team.models.CfgOtherUserMapping; + + +public interface OtherUserMappingDao extends JpaRepository { + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + + List findBySectionIdAndPropertyIdAndBookingTypeId(Long sectionId, Long propertyId, Long bookingTypeId); + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/team/repositories/SectionDao.java b/src/main/java/com/mgm/mcrm/basesetting/team/repositories/SectionDao.java new file mode 100644 index 0000000..b14aeb9 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/team/repositories/SectionDao.java @@ -0,0 +1,32 @@ +package com.mgm.mcrm.basesetting.team.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import com.mgm.mcrm.basesetting.team.models.CfgSections; + + +public interface SectionDao extends JpaRepository { + + + List findAll(Specification spec); + List findAll(Specification spec, Sort sort); + Page findAll(Specification spec, Pageable pageable); + + @Transactional + @Modifying + void deleteById(long id); + + @Query(value = "select * from cfg_sections with (nolock) where name=?1", nativeQuery = true) + CfgSections getByName(String name); + + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/team/repositories/TeamStructureDao.java b/src/main/java/com/mgm/mcrm/basesetting/team/repositories/TeamStructureDao.java new file mode 100644 index 0000000..94b3d90 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/team/repositories/TeamStructureDao.java @@ -0,0 +1,30 @@ +package com.mgm.mcrm.basesetting.team.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import com.mgm.mcrm.basesetting.team.models.CfgTeamStructure; + + +public interface TeamStructureDao extends JpaRepository { + + @Query(value = "select * from cfg_team_structure with (nolock) where division_id=?1 and department_id=?2 and section_id=?3", nativeQuery = true) + CfgTeamStructure getByDivisionIdAndDepartmentIdAndSectionId(Long divisionId,Long departmentId,Long sectionId); + + List findAll(Specification spec); + List findAll(Specification spec, Sort sort); + Page findAll(Specification spec, Pageable pageable); + + @Transactional + @Modifying + void deleteById(long id); + +} diff --git a/src/main/java/com/mgm/mcrm/basesetting/team/repositories/TeamStructureViewDao.java b/src/main/java/com/mgm/mcrm/basesetting/team/repositories/TeamStructureViewDao.java new file mode 100644 index 0000000..9ef626c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/basesetting/team/repositories/TeamStructureViewDao.java @@ -0,0 +1,36 @@ +package com.mgm.mcrm.basesetting.team.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import com.mgm.mcrm.basesetting.team.models.CfgTeamStructureView; + + +public interface TeamStructureViewDao extends JpaRepository { + + @EntityGraph(value = "graph.TeamStructure.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findAll(Specification spec); + @EntityGraph(value = "graph.TeamStructure.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findAll(Specification spec, Sort sort); + + Page findAll(Specification spec, Pageable pageable); + + //--For view page data + @EntityGraph(value = "graph.TeamStructure.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + + + @Transactional + @Modifying + void deleteById(long id); + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/controllers/BookingController.java b/src/main/java/com/mgm/mcrm/booking/controllers/BookingController.java new file mode 100644 index 0000000..83cc655 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/controllers/BookingController.java @@ -0,0 +1,954 @@ +package com.mgm.mcrm.booking.controllers; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +import com.auth0.jwt.JWT; +import com.mgm.mcrm.approval.service.ApprovalService; +import com.mgm.mcrm.appsetting.services.SettingService; +import com.mgm.mcrm.appsetting.services.SysSettingService; +import com.mgm.mcrm.authorization.dtos.LoginUserInfo; +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.authorization.utils.JwtTokenUtil; +import com.mgm.mcrm.basesetting.daylight.dtos.response.ProfileDetailResponse; +import com.mgm.mcrm.basesetting.daylight.services.DaylightService; +import com.mgm.mcrm.booking.dtos.daylight.requests.ChangeMiscChargeRequest; +import com.mgm.mcrm.booking.dtos.search.*; +import com.mgm.mcrm.booking.dtos.BookingDto; +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.booking.models.BookingsView; +import com.mgm.mcrm.booking.models.GamingData; +import com.mgm.mcrm.booking.services.*; +import com.mgm.mcrm.booking.services.mockup.BookingServiceMockup; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.common.dtos.data_import.ValidateResult; +import com.mgm.mcrm.common.dtos.data_import.booking.OtherBookingImportRow; +import com.mgm.mcrm.common.dtos.mgm_api.PlayerProfileEntry; +import com.mgm.mcrm.common.dtos.mgm_api.UserInfoApiRecord; +import com.mgm.mcrm.common.dtos.system.ResFileResult; +import com.mgm.mcrm.common.utils.*; +import com.mgm.mcrm.player.services.PlayerService; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.server.ResponseStatusException; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; + +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.constants.SysConstants; +import com.mgm.mcrm.common.annotation.logging.OperationLog; +import com.mgm.mcrm.common.utils.mockup.AjaxResultMockup; +import com.mgm.mcrm.appsetting.models.CfgSettings; +import com.mgm.mcrm.common.dtos.DataTableResult; + +@RestController +@CrossOrigin(origins = "*") +@RequestMapping("/api") +public class BookingController { + + @Resource + private BookingService bookingService; + @Resource + private OperaDBBookingService operaDBService; + @Resource + private NonMGMBookingService nonMGMService; + @Resource + private SettingService settingService; + @Resource + private SysSettingService sysSettingService; + @Resource + private OperaService operaSerivce; + @Resource + private PlayerService playerService; + @Resource + private MgmUserService mgmUserService; + @Resource + private WaitlistBookingService waitlistBookingService; + @Autowired + private DaylightService daylightService; + + @Resource + private BookingServiceMockup bookingServiceMockup; + @Resource + private ApprovalService approvalService; + + @Resource + private SysGroupPermissionService sysGroupPermissionService; + + + @RequestMapping(value = "/app/booking/get_bookings_by_nameId", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> getBookingsByNameId(HttpServletRequest request, + @RequestBody GetBookingByNameIdRequest params) { + Integer startIndex = params.getStartIndex(); + Integer pageSize = params.getPageSize(); + List nameId = params.getNameId(); + + BaseApiResponse result = AjaxResultMockup.mockupResult("\\mockup\\app\\getBookingsByNameId.json"); + + // 模拟一些数据,包括DUE IN, CHECKED IN, DUE OUT + JSONObject data = (JSONObject)result.getData(); + JSONArray bookings = data.getJSONArray("bookings"); + Date today = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd"); + if(bookings!=null && !bookings.isEmpty() && startIndex returnList = new ArrayList<>(); + for(int i=startIndex;i=bookings.size()) { + data.put("startIndex", -1); + }else { + data.put("startIndex", startIndex+pageSize); + } + } + else { + data.put("startIndex", -1); + } + + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @RequestMapping(value = {"/app/booking/get_opera_booking_by_conf", "/app/booking/get_booking_by_conf"}, method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity>> getBookingByConfirmationNo(HttpServletRequest request, + @RequestBody GetOperaBookingRequest params) throws Exception { + LoginUserInfo loginUser = SysCommon.parseUserFromToken(request); + String conf = params.getConf(); + + BaseApiResponse> result = new BaseApiResponse<>(); + + String userId = loginUser.getLoginId(); + String groupName = loginUser.getGroupName(); + //--get group permissions + boolean viewBooking = + sysGroupPermissionService.checkGroupPermission(groupName, SysConstants.PERMISSION_APP_VIEW_BOOKING); + boolean isMock = sysSettingService.isMockReplicate(); + isMock = false; + viewBooking = true; + + List list; + if(isMock) { + list = bookingServiceMockup.getBookingByConfirmationNoMock(conf); + }else { + list = bookingService.getBookingByConfirmationNo(conf); + } + if(!list.isEmpty() && StringUtils.isNotEmpty(userId)) { + BaseApiResponse findPlayerResult = + playerService.findPlayerProfileByPlayerIdAndUserId(list.getFirst().getPlayerId(), userId); + if(findPlayerResult.isSuccess()) { + PlayerProfileEntry profile = findPlayerResult.getData(); + Integer code = profile.getCodedFlag(); + if(code==1 && viewBooking) { + result.setSuccess(true); + result.setData(list); + }else { + result.setMessage("No permission to view"); + result.setSuccess(false); + } + }else { + result.setMessage(findPlayerResult.getMessage()); + result.setSuccess(false); + } + } else { + result.setMessage("Get booking by confirmationNo=" + conf + " failed, list size=" + list.size() + ", user=" + userId); + result.setSuccess(false); + } + + return ResponseEntity.status(HttpStatus.OK).body(result); + } + @RequestMapping(value = "/app/booking/get_booking_by_id", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity>> getBookingById( + HttpServletRequest request, + @RequestBody GetBookingByIdRequest params) { + Long bookingId = params.getId(); + + List list = new ArrayList<>(); + BaseApiResponse> result = new BaseApiResponse<>(); + result.setSuccess(false); + result.setData(list); + LoginUserInfo loginUser = SysCommon.parseUserFromToken(request); + String userId = loginUser.getLoginId(); + String groupName = loginUser.getGroupName(); + //--get group permissions + boolean viewBooking = sysGroupPermissionService.checkGroupPermission(groupName, "10001_01"); + + list = bookingService.getBookingById(bookingId); + + if(!list.isEmpty() && StringUtils.isNotEmpty(userId)) { + BaseApiResponse findPlayerProfileResult = + playerService.findPlayerProfileByPlayerIdAndUserId(list.getFirst().getPlayerId(), userId); + if(findPlayerProfileResult.isSuccess()) { + PlayerProfileEntry profile = findPlayerProfileResult.getData(); + Integer code = profile.getCodedFlag(); + viewBooking = true; + if(code==1 && viewBooking) { + result.setSuccess(true); + result.setData(list); + }else { + result.setMessage("No permission to view"); + } + }else { + result.setMessage(findPlayerProfileResult.getMessage()); + } + BookingsView book = list.getFirst(); + String aStatus = book.getApproveStatus(); + if(Strings.CS.equalsAny(aStatus, "WF", "WR", "WE", "WC")) { + result.setSuccess(true); + list = new ArrayList<>(); + list.add(new BookingsView()); + result.setData(list); + result.setMessage("Cannot view booking"); + } + } + + return ResponseEntity.status(HttpStatus.OK).body(result); + } + @RequestMapping(value = "/app/booking/get_bookings_by_groupId", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity>> getBookingsByGroupId( + HttpServletRequest request, + @RequestBody GetBookingByGroupRequest params) { + String groupId = params.getGroupId(); + BaseApiResponse> result = new BaseApiResponse<>(); + List list = bookingService.getBookingsByGroupId(groupId); + result.setSuccess(true); + result.setData(list); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @OperationLog(actionName="Create Booking", eventCode = "booking_create") + @RequestMapping(value = "/app/booking/create", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity>> createBooking(HttpServletRequest request, @RequestBody BookingDto booking) throws Exception { + LoginUserInfo loginUser = SysCommon.parseUserFromToken(request); + String userId = loginUser.getLoginId(); + String groupName = loginUser.getGroupName(); + String category = booking.getPropertyCategory(); + BaseApiResponse> result = new BaseApiResponse<>(); + //--get group permissions + boolean createBooking = false; + List userPermissions = sysGroupPermissionService.getRouterPermissionsByGroupName(groupName); + if(!userPermissions.isEmpty()) { + for(SysRouterPermission per:userPermissions) { + if(Strings.CS.equals(per.getId(), "10001_02") ) createBooking = true; + } + } + createBooking = true; + String playerId = booking.getPlayerId(); + BaseApiResponse findPlayerResult = playerService.findPlayerProfileByPlayerIdAndUserId(playerId, userId); + boolean testDaylight = true; + if(findPlayerResult.isSuccess()) { + PlayerProfileEntry profile = findPlayerResult.getData(); + Integer code = profile.getCodedFlag(); + if(code==1 && createBooking) { + BaseApiResponse userInfoRes = mgmUserService.findUserInfoByUserId(userId); + UserInfoApiRecord userInfo = userInfoRes.getData(); + BaseApiResponse> createResult = bookingService.createBooking(booking,request,userInfo,category); + if(createResult.isSuccess()) { + result.setSuccess(true); + result.setMessage("Create Success"); + result.setData(createResult.getData()); + result.setRequestData(createResult.getData()); + }else { + result.setSuccess(false); + result.setMessage("Create Failed with Error:" + createResult.getMessage()); + result.setCode(createResult.getCode()); + } + }else{ + result.setSuccess(false); + result.setCode("NO_PERMISSION"); + result.setMessage("No permission to create"); + } + }else { + result.setSuccess(false); + result.setCode("CALL_API_ERROR"); + result.setMessage(findPlayerResult.getMessage()); + } + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @OperationLog(actionName="Edit Booking", eventCode = "booking_edit") + @RequestMapping(value = "/app/booking/edit", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity>> editBooking(HttpServletRequest request, @RequestBody BookingDto booking) throws Exception { + LoginUserInfo loginUser = SysCommon.parseUserFromToken(request); + String userId = loginUser.getLoginId(); + String groupName = loginUser.getGroupName(); + String category = booking.getPropertyCategory(); + + BaseApiResponse> result = new BaseApiResponse<>(); + result.setRequestData(booking); + //--get group permissions + //TODO Test + boolean editBooking = false; +// List userPermissions = sysGroupPermissionService.getRouterPermissionsByGroupName(groupName); +// if(!userPermissions.isEmpty()) { +// for(SysRouterPermission per:userPermissions) { +// if(Strings.CS.equals(per.getId(), "10001_02") ) editBooking = true; +// } +// } + editBooking = true; + //TODO Test + String playerId = booking.getPlayerId(); + BaseApiResponse findPlayerResult = playerService.findPlayerProfileByPlayerIdAndUserId(playerId, userId); + if(findPlayerResult.isSuccess()) { + PlayerProfileEntry profile = findPlayerResult.getData(); + Integer code = profile.getCodedFlag(); + if(code==1 && editBooking) { + BaseApiResponse> editResult = bookingService.editBooking(booking,request,profile,category); + if(editResult.isSuccess()) { + result.setSuccess(true); + result.setMessage(!StringUtils.isEmpty(editResult.getMessage())?editResult.getMessage():"Edit Success"); + result.setData(editResult.getData()); + result.setRequestData(editResult.getData()); + }else { + result.setSuccess(false); + result.setMessage(editResult.getMessage()); + result.setCode(editResult.getCode()); + } + }else { + result.setSuccess(false); + result.setCode("NO_PERMISSION"); + result.setMessage("No permission to edit"); + } + }else { + result.setSuccess(false); + result.setCode("CALL_API_ERROR"); + result.setMessage(findPlayerResult.getMessage()); + } + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @OperationLog(actionName="Cancel Waitlist Booking", eventCode = "waitlist_booking_cancel") + @RequestMapping(value = "/app/booking/cancel_waitlist", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> cancelWaitlistBooking(HttpServletRequest request, + @RequestBody BookingDto booking) { + BaseApiResponse result = new BaseApiResponse<>(); + result.setRequestData(booking); + BaseApiResponse cancelResult = bookingService.cancelWaitlistBooking(booking,request); + if(cancelResult.isSuccess()) { + result.setSuccess(true); + result.setMessage("Cancel Success"); + result.setData(cancelResult.getData()); + }else { + result.setSuccess(false); + result.setMessage("Cancel Failed with Error:"+cancelResult.getMessage()); + result.setCode(cancelResult.getCode()); + } + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + // + @RequestMapping(value = "/app/booking/change_misc_charge", method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_VALUE) + public BaseApiResponse changeMisCharge(HttpServletRequest request, @RequestBody ChangeMiscChargeRequest params) throws Exception{ + BaseApiResponse processResult = new BaseApiResponse<>(); + + Long bookingId = params.getBookingId(); + String misCharge = params.getMisCharge(); + + String token = request.getHeader("Authorization"); + String userId = JWT.decode(token).getClaim("login_id").asString(); + String groupName = JWT.decode(token).getClaim("group_name").asString(); + + BaseApiResponse serviceResult = bookingService.changeMiscCharge(bookingId,misCharge,userId); + if(serviceResult.isSuccess()) { + processResult.setSuccess(true); + processResult.setMessage("Change MiscCharge Success"); + processResult.setData(processResult.getData()); + }else { + processResult.setSuccess(false); + processResult.setMessage("Change MiscCharge Failed"); + } + return processResult; + } + + @OperationLog(actionName="Approve Waitlist Booking", eventCode = "waitlist_booking_approve") + @RequestMapping(value = "/app/booking/approve_waitlist", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> approveWaitlistBooking(HttpServletRequest request, + @RequestBody BookingDto booking) { + BaseApiResponse result = new BaseApiResponse<>(); + result.setRequestData(booking); + BaseApiResponse approveResult = bookingService.approveWaitlistBooking(booking,request); + if(approveResult.isSuccess()) { + result.setSuccess(true); + result.setMessage("Cancel Success"); + result.setData(approveResult.getData()); + }else { + result.setSuccess(false); + result.setMessage("Cancel Failed with Error:"+approveResult.getMessage()); + result.setCode(approveResult.getCode()); + } + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @RequestMapping(value = "/app/bookings/search_optimize", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> recordSearchOptimize(HttpServletRequest request, + @RequestBody @Valid BookingSearchRequest searchRequest) throws Exception { + LogUtil.info(BookingService.class,"[recordSearch] start recordSearch "); + LoginUserInfo loginUser = SysCommon.parseUserFromToken(request); + return ResponseEntity.status(HttpStatus.OK).body(getRecordSearch_Optimize(searchRequest, loginUser)); + } + + public List getRecordSearch_Optimize(@NotNull BookingSearchRequest searchRequest, LoginUserInfo loginUser) throws Exception { + long recordSearchStartTime = System.currentTimeMillis(); + long stepStartTime = recordSearchStartTime; + PlayerProfileEntry memberInfo = searchRequest.getMember(); + String playerId = memberInfo.getPlayerId(); + String operaId =null; + List operaIds = memberInfo.getNameIds(); + if(operaIds!=null && !operaIds.isEmpty()){ + operaId = String.valueOf(operaIds.getFirst()); + } + List allPropertiesResults = new ArrayList<>(); + boolean isMock =sysSettingService.isMockReplicate(); + String userId = loginUser.getLoginId(); + + LogUtil.info(BookingService.class, "[recordSearch] userId:"+userId); + + if(!StringUtils.isEmpty(userId)) { + LogUtil.info(BookingService.class, "[recordSearch] findPlayer:"+playerId); + BaseApiResponse serviceResult = playerService.findPlayerProfileByPlayerIdAndUserId(playerId, userId); + LogUtil.info(BookingController.class, "[recordSearch] findPlayerProfile spendTime:" + (System.currentTimeMillis() - stepStartTime) + "ms"); + if(!serviceResult.isSuccess()) { + LogUtil.warn(BookingService.class,"[recordSearch] Player profile not found ["+serviceResult.getMessage()+"]"); + return allPropertiesResults; + } + } + + String currentDay = DateTimeUtil.getCurrentDate("yyyy-MM-dd"); + + CfgSettings bookingMaxNights = settingService.getSettingByKey(SysConstants.MAX_BOOKING_STAY_DAYS); + int maxNights = Integer.parseInt(bookingMaxNights.getKeyValues()); + String startDate = bookingService.getStartDate(currentDay, maxNights+60); + String checkOutDate = bookingService.getSearchRecordCheckOutDate(currentDay); + List operaResult = new ArrayList<>(); + List daylightResult = new ArrayList<>(); + //去Daylight查ProfileId + stepStartTime = System.currentTimeMillis(); + BaseApiResponse> profileResult = daylightService.dayLightGetProfileByPlayerId(playerId); + List returnData = profileResult.getData(); + if (profileResult.isSuccess()) { + //Daylight存在 则去Daylight查Record 在Daylight不存在的话 跳过 + ProfileDetailResponse profileDetailResponse = returnData.getFirst(); + daylightResult = daylightService.getBookingRecordByProfileId_Optimize(profileDetailResponse.getId(), playerId); + } else { + LogUtil.warn(BookingService.class, "[recordSearch] Daylight profile lookup failed, message=" + profileResult.getMessage() + ", playerId=" + playerId); + } + LogUtil.info(BookingService.class, "[recordSearch] getBookingsByNameID:"); + LogUtil.info(BookingController.class, "[recordSearch] getDaylightBookings resultSize:" + daylightResult.size() + " spendTime:" + (System.currentTimeMillis() - stepStartTime) + "ms"); + stepStartTime = System.currentTimeMillis(); + if(isMock) { + bookingService.changeStatus(); + operaResult = bookingServiceMockup.getSearchRecordMock_Optimize(startDate, checkOutDate, playerId); + operaResult = operaResult.stream().filter(item -> "OPERA".equalsIgnoreCase(item.getPropertyCategory())).toList(); + }else { + if(StringUtils.isNotBlank(operaId)) { + CfgSettings operaMaxSearch = settingService.getSettingByKey(SysConstants.MAX_OPERA_BOOKING_DAYS); + Date operaEndDay = DateTimeUtil.addDay(DateTimeUtil.getDateFromString(currentDay, "yyyy-MM-dd"), + Integer.valueOf(operaMaxSearch.getKeyValues())); + Date operaEndDate = DateTimeUtil.getDateFromString(DateTimeUtil.getDateByFormat(operaEndDay, "yyyy-MM-dd"), "yyyy-MM-dd"); + operaResult = operaDBService.getBookingsByNameID_Optimize(operaId, "All", operaEndDate); + LogUtil.info(BookingService.class, "[recordSearch] Opera booking list size=" + operaResult.size()); + } + } + + LogUtil.info(BookingController.class, "[recordSearch] getBookingsByNameID resultSize:" + operaResult.size() + " spendTime:" + (System.currentTimeMillis() - stepStartTime) + "ms"); + if (!daylightResult.isEmpty()) { + //将Daylight Result 合并至DB + LogUtil.info(BookingService.class,"[recordSearch] before mergeDaylightRecordFromDB_Optimize, playerId=" + + playerId + ", daylightResult.size=" + daylightResult.size()); + stepStartTime = System.currentTimeMillis(); + List dbDaylightResults = bookingService.mergeDaylightRecordFromDB_Optimize(daylightResult,memberInfo,userId); + LogUtil.info(BookingController.class, "[recordSearch] mergeDaylightDatabaseInfo resultSize:" + dbDaylightResults.size() + " spendTime:" + (System.currentTimeMillis() - stepStartTime) + "ms"); + stepStartTime = System.currentTimeMillis(); + bookingService.syncDaylightMergeBookingToDbAndPopulateIds_Optimize(dbDaylightResults); + LogUtil.info(BookingController.class, "[recordSearch] syncDaylightDatabase resultSize:" + dbDaylightResults.size() + " spendTime:" + (System.currentTimeMillis() - stepStartTime) + "ms"); + dbDaylightResults.removeIf(item -> "CANCELED".equalsIgnoreCase(item.getLastOperaStatus())); + + allPropertiesResults.addAll(dbDaylightResults); + } else { + LogUtil.warn(BookingService.class,"[recordSearch] daylightResult is empty, skipping Daylight merge"); + } + + List dbOperaResults = new ArrayList<>(); + if (!operaResult.isEmpty()) { + //将Opera Result 合并至DB + LogUtil.info(BookingService.class,"[recordSearch] mergeOperaRecoredToDatabaseInfo:"); +// for (BookingDto o : operaResult) { +// LogUtil.info(BookingService.class, "[recordSearch] Opera before merge: confNo=" + o.getConfirmationNo() +// + ", hotelCode=" + o.getHotelCode() + ", id=" + o.getId() + ", status=" + o.getLastOperaStatus()); +// } + stepStartTime = System.currentTimeMillis(); + dbOperaResults = bookingService.mergeOperaRowFromExistDbBooking_Optimize(operaResult,memberInfo,userId); + LogUtil.info(BookingController.class, "[recordSearch] mergeOperaDatabaseInfo resultSize:" + dbOperaResults.size() + " spendTime:" + (System.currentTimeMillis() - stepStartTime) + "ms"); +// for (BookingDto o : dbOperaResults) { +// LogUtil.info(BookingService.class, "[recordSearch] Opera after merge: confNo=" + o.getConfirmationNo() +// + ", hotelCode=" + o.getHotelCode() + ", id=" + o.getId() + ", status=" + o.getLastOperaStatus() +// + ", approveStatus=" + o.getApproveStatus() + ", pendingRevisionId=" + o.getPendingRevisionId()); +// } + allPropertiesResults.addAll(dbOperaResults); + } + + //-- sync Opera bookings to DB (Daylight bookings already synced via syncDaylightMergeBookingToDbAndPopulateIds_Optimize) + if(!dbOperaResults.isEmpty()){ + stepStartTime = System.currentTimeMillis(); + bookingService.syncMergeBookingToDb_Optimize(dbOperaResults); + LogUtil.info(BookingController.class, "[recordSearch] dispatchOperaSync resultSize:" + dbOperaResults.size() + " spendTime:" + (System.currentTimeMillis() - stepStartTime) + "ms"); + } + + //-- hide booking with pending revisions, instead, shows the pending version or waitlist booking + long removedByPendingRevision = allPropertiesResults.stream().filter(item -> item.getPendingRevisionId() != null).count(); + if (removedByPendingRevision > 0) { + LogUtil.info(BookingService.class, "[recordSearch] removeIf pendingRevisionId, removedCount=" + removedByPendingRevision); + allPropertiesResults.stream().filter(item -> item.getPendingRevisionId() != null).forEach(item -> + LogUtil.info(BookingService.class, "[recordSearch] removed by pendingRevisionId: id=" + item.getId() + + ", confNo=" + item.getConfirmationNo() + ", pendingRevisionId=" + item.getPendingRevisionId())); + } + allPropertiesResults.removeIf(item -> item.getPendingRevisionId() != null); + + //-- + LogUtil.info(BookingService.class,"[recordSearch] getSearchRecordPending:"); + stepStartTime = System.currentTimeMillis(); + List listPending = bookingService.getSearchRecordPending_Optimize(startDate, checkOutDate, playerId); + LogUtil.info(BookingController.class, "[recordSearch] getSearchRecordPending resultSize:" + listPending.size() + " spendTime:" + (System.currentTimeMillis() - stepStartTime) + "ms"); + + allPropertiesResults.addAll(listPending); + //-- Get Non-MGM booking + LogUtil.info(BookingService.class, + "[recordSearch] getNONMGMBookingsByPlayer:"); + stepStartTime = System.currentTimeMillis(); + List nonMGMDBResult = nonMGMService.getDBBookingsByPlayer_Optimize(playerId); + LogUtil.info(BookingController.class, "[recordSearch] getNONMGMBookingsByPlayer resultSize:" + nonMGMDBResult.size() + " spendTime:" + (System.currentTimeMillis() - stepStartTime) + "ms"); + allPropertiesResults.addAll(nonMGMDBResult); + + //-- Get Waitlist booking + LogUtil.info(BookingService.class, + "[recordSearch] getWailistBookingsByPlayer:"); + //db waitlist + stepStartTime = System.currentTimeMillis(); + List waitlistDBResult = waitlistBookingService.getWaitlistBookingByPlayerId_Optimize(playerId); + LogUtil.info(BookingController.class, "[recordSearch] getWaitlistBookingByPlayerId resultSize:" + waitlistDBResult.size() + " spendTime:" + (System.currentTimeMillis() - stepStartTime) + "ms"); + allPropertiesResults.addAll(waitlistDBResult); + + //-- + LogUtil.info(BookingService.class, + "[recordSearch] getSearchRecordPendingApproval:"); + stepStartTime = System.currentTimeMillis(); + List listPendingApproval = approvalService.getSearchRecordPendingApproval(startDate, checkOutDate,playerId); + LogUtil.info(BookingController.class, "[recordSearch] getSearchRecordPendingApproval resultSize:" + listPendingApproval.size() + " spendTime:" + (System.currentTimeMillis() - stepStartTime) + "ms"); + allPropertiesResults.addAll(listPendingApproval); + + LogUtil.info(BookingService.class,"[recordSearch] before filterAndSortBookingResult, total=" + + allPropertiesResults.size() + ", daylightCount=" + + allPropertiesResults.stream().filter(item -> StringUtils.isNotBlank(item.getDlReservationId())).count() + + ", daylightStatusSummary=" + summarizeDaylightStatuses(allPropertiesResults)); + stepStartTime = System.currentTimeMillis(); + allPropertiesResults = this.filterAndSortBookingResult(allPropertiesResults); + LogUtil.info(BookingController.class, "[recordSearch] filterAndSortResult resultSize:" + allPropertiesResults.size() + " spendTime:" + (System.currentTimeMillis() - stepStartTime) + "ms"); + LogUtil.info(BookingService.class,"[recordSearch] after filterAndSortBookingResult, total=" + + allPropertiesResults.size() + ", daylightCount=" + + allPropertiesResults.stream().filter(item -> StringUtils.isNotBlank(item.getDlReservationId())).count() + + ", daylightStatusSummary=" + summarizeDaylightStatuses(allPropertiesResults)); + + // 过滤掉所有WA的booking + allPropertiesResults.removeIf(item -> "WA".equalsIgnoreCase(item.getApproveStatus())); + + LogUtil.info(BookingController.class, "[recordSearch] total resultSize:" + allPropertiesResults.size() + " spendTime:" + (System.currentTimeMillis() - recordSearchStartTime) + "ms"); + return allPropertiesResults; + } + + private String summarizeDaylightStatuses(List bookings) { + Map statusSummary = bookings.stream() + .filter(item -> StringUtils.isNotBlank(item.getDlReservationId())) + .collect(Collectors.groupingBy( + item -> "approveStatus=" + Objects.toString(item.getApproveStatus(), "null") + + ",lastOperaStatus=" + Objects.toString(item.getLastOperaStatus(), "null"), + LinkedHashMap::new, + Collectors.counting())); + return statusSummary.toString(); + } + + private List filterAndSortBookingResult(List allPropertiesResults){ + // Deduplicate by id (no pre-sort needed): last entry with same id wins, which matches + // the previous "sort-by-id-desc then keep-first" behaviour since later items in the + // original list overwrite earlier ones. + Map dedupMap = new LinkedHashMap<>(); + List noIdBookings = new ArrayList<>(); + for (BookingDto book : allPropertiesResults) { + if (StringUtils.isBlank(book.getConfirmationNo()) || book.getId() == null) { + noIdBookings.add(book); + } else { + String idKey = String.valueOf(book.getId()); + BookingDto existing = dedupMap.put(idKey, book); + if (existing != null) { + LogUtil.info(BookingService.class, "[recordSearch] DUPLICATE REMOVED: id=" + existing.getId() + + ", confNo=" + existing.getConfirmationNo() + ", hotelCode=" + existing.getHotelCode() + + ", dlReservationId=" + existing.getDlReservationId() + + ", lastOperaStatus=" + existing.getLastOperaStatus()); + } + } + } + List removeDuplicateList = new ArrayList<>(dedupMap.values()); + removeDuplicateList.addAll(noIdBookings); + LogUtil.info(BookingService.class, "[recordSearch] after dedup: before=" + allPropertiesResults.size() + + ", after=" + removeDuplicateList.size()); + //check show yesterday booking + CfgSettings cutoffStartTime = settingService.getSettingByKey("VIEW_YESTERDAY_TODOLIST_START"); + String cutoffStartTimeValue = cutoffStartTime.getKeyValues(); + CfgSettings cutoffEndTime = settingService.getSettingByKey("VIEW_YESTERDAY_TODOLIST_END"); + String cutoffEndTimeValue = cutoffEndTime.getKeyValues(); + Date curoffDate = DateTimeUtil.getTodoYesterdayDay(cutoffStartTimeValue, cutoffEndTimeValue); + + allPropertiesResults = removeDuplicateList; + for (int i = allPropertiesResults.size() - 1; i >= 0; i--) { + BookingDto iPro = allPropertiesResults.get(i); + // delete UNKNOWN and CANCELED(no keyword) data + if (Strings.CS.equals("N", iPro.getApproveStatus()) && + (Strings.CS.equals(iPro.getLastOperaStatus(), "UNKNOWN") || (Strings.CS.equals(iPro.getLastOperaStatus(), "CANCELED")) ) ) { + LogUtil.info(BookingService.class, "[recordSearch] FILTERED status: id=" + iPro.getId() + + ", confNo=" + iPro.getConfirmationNo() + ", approveStatus=" + iPro.getApproveStatus() + + ", lastOperaStatus=" + iPro.getLastOperaStatus()); + allPropertiesResults.remove(i); + continue; + } + + if (Strings.CS.equals("C", iPro.getApproveStatus())) { +// LogUtil.info(BookingService.class, "[recordSearch] FILTERED approveStatus=C: id=" + iPro.getId() +// + ", confNo=" + iPro.getConfirmationNo() + ", lastOperaStatus=" + iPro.getLastOperaStatus()); + allPropertiesResults.remove(i); + continue; + } + + // delete Finsihed Pending Booking + if (Strings.CS.equals("N", iPro.getApproveStatus())&& (iPro.getRevisionOf()!=null)) { + LogUtil.info(BookingService.class, "[recordSearch] FILTERED finishedPending: id=" + iPro.getId() + + ", confNo=" + iPro.getConfirmationNo() + ", revisionOf=" + iPro.getRevisionOf()); + allPropertiesResults.remove(i); + continue; + } + + //remove yesterday booking + //只过滤「checkin<今天 && checkout<今天」的过去预订(即未入住就过期的 no-show 候选) + //对于在住中的预订(checkin<今天 但 checkout>=今天),即使状态是 RESERVED/DUE_IN 也要展示 + //NO_SHOW / CANCELED 等终态状态由上面的规则(approveStatus=C / lastOperaStatus=CANCELED)处理 + if(iPro.getCheckinDate().getTime()>> getBookingByPage( + HttpServletRequest request, + @RequestBody(required=true) BookingQueryRequest queryFilter) throws Exception { +// requireAnyWebPermission(request, "00501_01", "00401_01"); + if(StringUtils.isNotBlank(queryFilter.getPermissionId())) { + String groupName = "NO_GROUP"; + LoginUserInfo loginUser = SysCommon.parseUserFromToken(request); + if(loginUser!=null) { + if(loginUser.getId()!=null && Strings.CS.equals(SysConstants.SUPER_ADMIN_ID,""+loginUser.getId())) { + queryFilter.setPermissionId(""); + }else if(StringUtils.isNotBlank(loginUser.getGroupName())) { + groupName = loginUser.getGroupName(); + } + } + queryFilter.setPermissionGroup(groupName); + } + return ResponseEntity.status(HttpStatus.OK).body(processPageRequest(queryFilter)); + } + + private BaseApiResponse> processPageRequest(BookingQueryRequest queryFilter) throws Exception { + BaseApiResponse> result = new BaseApiResponse<>(); + //-- + DataTableResult resultData = bookingService.getBookingByPage(queryFilter); + //check gaming data + if(resultData.getTotalRecords()>0) { + List rowData = resultData.getRowData(); + List bookIds = new ArrayList<>(); + for(BookingsView r:rowData) { + if(Strings.CS.equals("W", r.getApproveStatus())) { + bookIds.add(String.valueOf(r.getId())); + if(bookIds.size()==20) { + String bookId = String.join(";", bookIds); + List gamingData = waitlistBookingService.syncWaitlistData(bookId); + bookIds = new ArrayList<>(); + } + } + } + if(!bookIds.isEmpty()) { + String bookId = String.join(";", bookIds); + List gamingData = waitlistBookingService.syncWaitlistData(bookId); + } + resultData = bookingService.getBookingByPage(queryFilter); + } + result.setData(resultData); + result.setSuccess(true); + result.setMessage("Query Success"); + return result; + } + + @RequestMapping(value = "/web/bookings/search", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> webRecordSearch(HttpServletRequest request, @RequestBody WebRecordSearchRequest params) throws Exception { +// requireAnyWebPermission(request, "00501_01", "00401_01", "00402_01"); + List list = getWebRecordSearch(request, params); + return ResponseEntity.status(HttpStatus.OK).body(list); + } + + public List getWebRecordSearch(HttpServletRequest request, + WebRecordSearchRequest params) throws Exception { + PlayerProfileEntry member = params.getMember(); + List operaId = member.getNameIds(); + String userId = params.getUserId(); + if(!StringUtils.isEmpty(userId)) { + userId = userId.replace("@mgm.mo", ""); + } + LogUtil.info(BookingService.class, + "[getWebRecordSearch] userId:"+userId); + + String currentDay = DateTimeUtil.getCurrentDate("yyyy-MM-dd"); + + CfgSettings bookingMaxNights = settingService.getSettingByKey(SysConstants.MAX_BOOKING_STAY_DAYS); + int maxNights = Integer.parseInt(bookingMaxNights.getKeyValues()); + + String startDate = bookingService.getStartDate(currentDay, maxNights+60); + String checkOutDate = bookingService.getSearchRecordCheckOutDate(currentDay); + + String playerId = params.getMember().getPlayerId(); + + List results = new ArrayList<>(); + LogUtil.info(BookingService.class, + "[getWebRecordSearch] getBookingsByNameID:"); + + List daylightResult = List.of(); + List operaResult = List.of(); + List otherResult = List.of(); + + if (SysCommon.mgmApiMockup) { + results = bookingServiceMockup.getSearchRecordMock(startDate, checkOutDate, playerId); +// results.removeIf(item -> !"OPERA".equalsIgnoreCase(item.getPropertyCategory())); + + daylightResult = results.stream() + .filter(item -> "DAYLIGHT".equalsIgnoreCase(item.getPropertyCategory())) + .collect(Collectors.toList()); + + operaResult = results.stream() + .filter(item -> "OPERA".equalsIgnoreCase(item.getPropertyCategory())) + .collect(Collectors.toList()); + + } else if(operaId != null && !operaId.isEmpty()) { + Date operaEndDay = new Date(); + CfgSettings operaMaxSearch = settingService.getSettingByKey(SysConstants.MAX_OPERA_BOOKING_DAYS); + operaEndDay = DateTimeUtil.addDay(DateTimeUtil.getDateFromString(currentDay, "yyyy-MM-dd"), + Integer.valueOf(operaMaxSearch.getKeyValues())); + Date operaEndDate = DateTimeUtil.getDateFromString(DateTimeUtil.getDateByFormat(operaEndDay, "yyyy-MM-dd"), "yyyy-MM-dd"); + results = operaDBService.getBookingsByNameID(String.valueOf(operaId.getFirst()), "All", operaEndDate); + } + + LogUtil.info(BookingService.class, + "[recordSearch] mergeDatabaseInfo:"); + List dbResults1; + if (SysCommon.mgmApiMockup) { + dbResults1 = bookingService.mergeOperaRecordToDatabaseInfo(operaResult, member, userId); + } else { + dbResults1 = bookingService.mergeOperaRecordToDatabaseInfo(results, member,userId); + } + + List dbResults2 = bookingService.mergeDaylightRecordToDatabaseInfo(daylightResult,member,userId); + List allPropertiesResults = new ArrayList<>(); + + allPropertiesResults.addAll(dbResults1); + allPropertiesResults.addAll(dbResults2); + allPropertiesResults.addAll(results); + + LogUtil.info(BookingService.class, + "[getWebRecordSearch] getSearchRecordPending:"); + + return allPropertiesResults; + } + + @RequestMapping(value = "/web/other_booking/import_batch", method = RequestMethod.POST) + public ResponseEntity> batchImportRows(HttpServletRequest request, HttpServletResponse response, + @RequestBody(required=false) List importRows) throws Exception{ +// requireAnyWebPermission(request, "00402_07"); + BaseApiResponse result = new BaseApiResponse<>(); + if(importRows==null || importRows.size()<=0) { + result.setSuccess(false); + result.setMessage("Empty import data"); + }else { + BaseApiResponse importResult = nonMGMService.importBatch(importRows,request); + result.setSuccess(importResult.isSuccess()); + result.setMessage(importResult.getMessage()); + result.setData(importResult.getData()); + } + result.setLogMessage(LogUtil.getAjaxFormatLog(result, "Import Other Booking", null, null)); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @RequestMapping(value = "/web/other_booking/upload_excel", method = RequestMethod.POST) + public ResponseEntity> uploadExcel(HttpServletRequest request, HttpServletResponse response, + @RequestBody(required=false) MultipartFile[] files) throws Exception{ +// requireAnyWebPermission(request, "00402_07"); + BaseApiResponse result = new BaseApiResponse<>(); + if(files==null || files.length<=0) { + result.setSuccess(false); + result.setMessage("Empty upload file"); + }else { + MultipartFile uploadFile = files[0]; + ResFileResult tmpFileRes = ExcelUtils.transTempFile(uploadFile); + if(tmpFileRes.isSuccess()) { + BaseApiResponse parseResult = nonMGMService.parseImportExcel(tmpFileRes.getFilePath()); + ExcelUtils.clearTempFile(tmpFileRes.getFilePath()); + if(parseResult.isSuccess()) { + result.setSuccess(true); + result.setMessage(parseResult.getMessage()); + result.setData(parseResult.getData()); + }else { + result.setSuccess(false); + result.setMessage(parseResult.getMessage()); + } + }else{ + result.setSuccess(false); + result.setMessage("Write import temp file failed:"+tmpFileRes.getErrorMessage()); + } + } + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @RequestMapping(value = "/web/booking/get_gaming_data", produces = "application/json;charset=UTF-8", method = RequestMethod.POST) + public ResponseEntity>> getGamingData(HttpServletRequest request, + @RequestBody(required=true) BookingQueryRequest queryFilter) throws Exception { +// requireAnyWebPermission(request, "00401_09"); + //-- + if(StringUtils.isNotBlank(queryFilter.getPermissionId())) { + String groupName = "NO_GROUP"; + LoginUserInfo loginUser = SysCommon.parseUserFromToken(request); + if(loginUser!=null) { + if(loginUser.getId()!=null && SysConstants.SUPER_ADMIN_ID.equals(""+loginUser.getId())) { + queryFilter.setPermissionId(""); + }else if(StringUtils.isNotBlank(loginUser.getGroupName())) { + groupName = loginUser.getGroupName(); + } + } + queryFilter.setPermissionGroup(groupName); + } + BaseApiResponse> result = refreshGamingDataByExport(queryFilter); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + // Calendar r566/r567 method-level permissions, using Daylight identity/services. + // The authenticated group, not a caller-supplied permissionId, grants access. + private void requireAnyWebPermission(HttpServletRequest request, String... permissionIds) { + LoginUserInfo user = JwtTokenUtil.parseUserFromRequest(request); + + if (user != null && user.getId().equals(1L)) return; + + if (user != null && StringUtils.isNotBlank(user.getGroupName())) { + + for (String permissionId : permissionIds) { + if (sysGroupPermissionService.checkGroupPermission(user.getGroupName(), permissionId)) { + return; + } + } + } + throw new ResponseStatusException(HttpStatus.FORBIDDEN, "NO PERMISSION"); + } + + private BaseApiResponse> refreshGamingDataByExport(BookingQueryRequest queryFilter) throws Exception { + BaseApiResponse> result = new BaseApiResponse<>(); + //-- + List rowData = bookingService.getBookingForRefreshGamingData(queryFilter); + List bookIds = new ArrayList<>(); + List searchStatus = DaoUtil.parseMultipleFilter(queryFilter.getSearchStatus()); + //check gaming data + if(!rowData.isEmpty()) { + //通过stream流筛选出对应的Status + bookIds = rowData.stream() + .filter(r -> searchStatus.contains(r.getApproveStatus())) + .map(r -> String.valueOf(r.getId())) + .collect(Collectors.toList()); + List> futures = new ArrayList<>(); + for (int i = 0; i < bookIds.size(); i += 20) { + int end = Math.min(i + 20, bookIds.size()); + List batch = bookIds.subList(i, end); + String bookId = String.join(";", batch); + //执行异步操作 + CompletableFuture future = CompletableFuture.runAsync(() -> { + try { + waitlistBookingService.syncWaitlistData(bookId); + } catch (Exception ignored) { + } + }); + futures.add(future); + } + // 等待所有异步操作完成 + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); + } + result.setData(bookIds); + result.setSuccess(true); + result.setMessage("Query Success"); + return result; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/controllers/WaitlistController.java b/src/main/java/com/mgm/mcrm/booking/controllers/WaitlistController.java new file mode 100644 index 0000000..baf56a2 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/controllers/WaitlistController.java @@ -0,0 +1,86 @@ +package com.mgm.mcrm.booking.controllers; + +import com.mgm.mcrm.authorization.dtos.LoginUserInfo; +import com.mgm.mcrm.booking.dtos.WebBatchUpdateWaitlistRequest; +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.annotation.logging.OperationLog; +import com.mgm.mcrm.booking.services.WaitlistBookingService; +import com.mgm.mcrm.logging.services.SysLogOperationService; +import com.mgm.mcrm.common.utils.LogUtil; + + +@RestController +@CrossOrigin(origins = "*") +@RequestMapping("/api") +public class WaitlistController { + + @Resource + private WaitlistBookingService waitlistService; + @Resource + private SysLogOperationService sysAuditLogService; + + @OperationLog(eventCode="booking_update",actionName="Update Waitlist Booking Status") + @RequestMapping(value = "/web/waitlist/update_waitlist_status", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> updateWaitlistStatus(HttpServletRequest request, + @RequestBody Bookings booking) throws Exception { + BaseApiResponse result = new BaseApiResponse<>(); + //-- + if(booking.getId()==null) { + result.setSuccess(false); + result.setCode("ERR_ILLEGAL_DATA"); + result.setMessage("Id can't be empty"); + }else { + //-- + LoginUserInfo userInfo =SysCommon.parseUserFromToken(request); + if (userInfo != null) { + booking.setUpdatedBy(userInfo.getLoginId()); + } + BaseApiResponse serviceResult = waitlistService.updateWaitlistBookingStatus(booking,request); + if(serviceResult.isSuccess()) { + result.setSuccess(true); + result.setMessage("Update Success"); + result.setData(serviceResult.getData()); + }else { + result.setSuccess(false); + result.setMessage("Update Failed with Error:"+serviceResult.getMessage()); + result.setCode(serviceResult.getCode()); + } + } + result.setLogMessage(LogUtil.getAjaxFormatLog(result, "Update Waitlist Booking Status", new String[] {"id","name"}, new String[] {"name"})); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + + @OperationLog(eventCode="booking_update",actionName="Update Waitlist Batch Booking Status") + @RequestMapping(value = "/web/waitlist/update_batch_waitlist_status", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> updateBatchWaitlistStatus(HttpServletRequest request, + @RequestBody WebBatchUpdateWaitlistRequest params) throws Exception { + BaseApiResponse result = new BaseApiResponse<>(); + String[] bookIds = params.getBookId().split(";"); + String status = params.getStatus(); + boolean change = params.isChange(); + result.setRequestData(bookIds); + BaseApiResponse serviceResult = waitlistService.updateBatchWaitlistBookingStatus(bookIds,status,request,change); + if(serviceResult.isSuccess()) { + result.setSuccess(true); + result.setMessage("Update Success"); + result.setData(serviceResult.getData()); + }else { + result.setSuccess(false); + result.setMessage("Update Failed with Error:"+serviceResult.getMessage()); + result.setCode(serviceResult.getCode()); + } + result.setLogMessage(LogUtil.getAjaxFormatLog(result, "Update Batch Waitlist Booking Status", new String[] {"id","name"}, new String[] {"name"})); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/BookingCancelInfo.java b/src/main/java/com/mgm/mcrm/booking/dtos/BookingCancelInfo.java new file mode 100644 index 0000000..a0673fb --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/BookingCancelInfo.java @@ -0,0 +1,15 @@ +package com.mgm.mcrm.booking.dtos; + +import lombok.Data; + +import java.util.Date; + +@Data +public class BookingCancelInfo { + private Long bookingId; + private Long propertyId; + private Long roomId; + private Long blockId; + private Date checkinDate; + private Date checkoutDate; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/BookingDateEntry.java b/src/main/java/com/mgm/mcrm/booking/dtos/BookingDateEntry.java new file mode 100644 index 0000000..b093606 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/BookingDateEntry.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.booking.dtos; + +import lombok.Data; + +import java.util.List; + +@Data +public class BookingDateEntry { + private List date; + private Integer status; + private boolean checked; + private String remark; + private int numOfNight; + private int numOfRoom; + private boolean submit; + private String bookingStatus; + private Integer isPost; + private Integer depositType; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/BookingDto.java b/src/main/java/com/mgm/mcrm/booking/dtos/BookingDto.java new file mode 100644 index 0000000..48545a8 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/BookingDto.java @@ -0,0 +1,164 @@ +package com.mgm.mcrm.booking.dtos; + +import com.alibaba.fastjson.JSONArray; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.mgm.mcrm.common.dtos.mgm_api.PlayerProfileEntry; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +@Data +public class BookingDto { + + private Long id; + private Long revisionOf; + private String confirmationNo; + private String resvId; + private String lastOperaStatus; + private String playerId; + private PlayerProfileEntry member; + private String memberTitle; + private String memberFirstName; + private String memberLastName; + @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") + private Date checkinDate; + @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") + private Date checkoutDate; + private Long propertyId; + private Long roomTypeId; + private String dlProfileId; + private String notifyLanguage; + private Double paymentAmount; + private Double operaTotal; + private String comment; + private String ratePlanCode; + private String chainCode; + private String hotelCode; + private String roomTypeCode; + private String promotionCode; + private String dlGuaranteeTypeId; + private String paymentType; + private String marketCode; + private String dlSourceId; + private String sourceCode; + private String cancelledBy; + private Date cancelledAt; + private Long sectionId; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + private Date createdAt; + private String createdBy; + @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") + private Date updatedAt; + private String updatedBy; + private String approveStatus; + private String remark; + private String bookType; + private String dlBlockId; + private Integer numOfNight; + private String sectionName; + private String booker; + private String mscRemark; + private String approvalRemark; + private String room; + private String sharer; + private String featureCode; + private String itemCode; + private String groupId; + private String propertyName; + private String block; + private Long blockId; + private String blockCode; + private Long roomId; + private String propertyCategory; + private Long bedTypeMasterGroupId; + private String operaComment; + private Long bedTypeId; + private String bedTypeName; + private String createdByName; + private String dateLists; + private String roomCN; + private String errorMessage; + private Integer tryTime; + @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") + private Date failedAt; + private String bookingTypeName; + private String roomCategory; + private Integer roomForBooking; + private Integer roomForWaitlist; + private Long segmentId; + private Date requestedCoDate; + private String tier; + private Long gamingId; + private String overlapBooking; + private String maBooking; + private String r3TheoWin; + private String r3Tpd; + private String r3ActualWin; + private String r6TheoWin; + private String r6Tpd; + private String r6ActualWin; + private String r12TheoWin; + private String r12Tpd; + private String r12ActualWin; + private String finalSegment; + private String tripTheoProfit; + private String dailyTheoProfit; + private String playerType; + private String rankingByPlayer; + private String bookerTeam; + private String currentTripTheoWinAmount; + private String last2dayTheoWinAmount; + private Long approvedId; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + private Date approvedAt; + private String approvedBy; + private String propertyEmailName; + private String roomEmailName; + private String eta; + private String etaTime; + private String changeCheckinDate; + private String changeCheckoutDate; + private String dlChannelId; + private String dlAccountId; + private String dlReservationId; + private Integer processStatus; + private Long bookingTypeId; + + private String status; + private Long pendingRevisionId; + private String specialName; + private List dateList; + private JSONArray sharerList; + private String memberTier; + private String sharerName; + private String expDate; + private String profieExpDate; + private String roomNo; + private boolean isShare; + private boolean isQueue; + private String dlPropertyId; + private String dlRoomTypeId; + private String specialCode; + private Integer DepositType; + private Integer isPost; + private List extendDate; + private String checkInDateVal; + private String checkOutDateVal; + private BookingUserEntry user; + private String userId; + private String userName; + private String dlExternalNo; + private String dlPurchaseElementId; + private Integer isApproval; + private String routerToApproverId; + private String requestReasonId; + private String routerToApproverName; + private String routingReason; + //--Merge Operation + private Date dataTime; + private String mergeOperation; + private BookingCancelInfo cancelInfo; + + private String miscCharge; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/BookingUserEntry.java b/src/main/java/com/mgm/mcrm/booking/dtos/BookingUserEntry.java new file mode 100644 index 0000000..412b551 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/BookingUserEntry.java @@ -0,0 +1,9 @@ +package com.mgm.mcrm.booking.dtos; + +import lombok.Data; + +@Data +public class BookingUserEntry { + private String userId; + private String userName; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/WebBatchUpdateWaitlistRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/WebBatchUpdateWaitlistRequest.java new file mode 100644 index 0000000..5afd3d2 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/WebBatchUpdateWaitlistRequest.java @@ -0,0 +1,10 @@ +package com.mgm.mcrm.booking.dtos; + +import lombok.Data; + +@Data +public class WebBatchUpdateWaitlistRequest { + private String bookId; + private String status; + private boolean change; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/daylight/AmountLock.java b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/AmountLock.java new file mode 100644 index 0000000..91120a7 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/AmountLock.java @@ -0,0 +1,5 @@ +package com.mgm.mcrm.booking.dtos.daylight; + +public class AmountLock { + private String behavior; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/daylight/Breakdown.java b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/Breakdown.java new file mode 100644 index 0000000..6b6ea33 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/Breakdown.java @@ -0,0 +1,23 @@ +package com.mgm.mcrm.booking.dtos.daylight; + +import com.mgm.mcrm.player.dtos.BasePricePerDay; +import com.mgm.mcrm.player.dtos.RatePricingDetail; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +@Data +public class Breakdown { + + private String fromDate; + private String toDate; + private String marketSegmentId; + private String type; + private List guests; + private RatePricingDetail ratePricingDetails; + private BasePricePerDay rateBasePricePerDay; + private BasePricePerDay basePricePerDay; + private AmountLock amountLock; + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/daylight/GuestForBreakdown.java b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/GuestForBreakdown.java new file mode 100644 index 0000000..9bfc49b --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/GuestForBreakdown.java @@ -0,0 +1,9 @@ +package com.mgm.mcrm.booking.dtos.daylight; + +import lombok.Data; + +@Data +public class GuestForBreakdown { + private String ageBucketId; + private Long count; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/ChangeMiscChargeRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/ChangeMiscChargeRequest.java new file mode 100644 index 0000000..97079e5 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/ChangeMiscChargeRequest.java @@ -0,0 +1,11 @@ +package com.mgm.mcrm.booking.dtos.daylight.requests; + +import lombok.Data; + +@Data +public class ChangeMiscChargeRequest { + + private String misCharge; + + private Long bookingId; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/AccompanyingGuestDTO.java b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/AccompanyingGuestDTO.java new file mode 100644 index 0000000..d76f671 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/AccompanyingGuestDTO.java @@ -0,0 +1,9 @@ +package com.mgm.mcrm.booking.dtos.daylight.requests.createReservation; + +import lombok.Data; + +@Data +public class AccompanyingGuestDTO { + + private String profileId; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/IndividualDTO.java b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/IndividualDTO.java new file mode 100644 index 0000000..2fcea84 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/IndividualDTO.java @@ -0,0 +1,121 @@ +package com.mgm.mcrm.booking.dtos.daylight.requests.createReservation; + +import com.alibaba.fastjson.annotation.JSONField; +import com.mgm.mcrm.booking.enums.ProfileTierEnums; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +import java.util.List; + +@Data +public class IndividualDTO { + + @JSONField(name = "_refId") + private String refId; + private String typeCode; + private IndividualDetailsDTO details; + private List memberships; + + // 方便使用 + @JSONField(serialize = false, deserialize = false) + private String memRefId; + @JSONField(serialize = false, deserialize = false) + private String memberLevelCode; + @JSONField(serialize = false, deserialize = false) + private String memberTypeCode; + + @Data + public static class IndividualDetailsDTO { + + private String firstName; + private String lastName; + } + + @Data + public static class MembershipDTO { + + private String typeCode; + private String levelCode; + private String number; + + @JSONField(name = "_refId") + private String refId; + } + + public static IndividualDTO buildNewProfileWithPlayerId( + String playerId, + String playerName, + String membershipRefId, + String profileRefId, + String tierName + ) { + IndividualDTO newProfileDto = new IndividualDTO(); + IndividualDTO.IndividualDetailsDTO newProfileDetail = new IndividualDTO.IndividualDetailsDTO(); + IndividualDTO.MembershipDTO membershipDto = new IndividualDTO.MembershipDTO(); + + String[] s = playerName.split(" "); + + if (s.length == 1) { + String theName = s[0]; + String substring = theName.substring(0, 1); + String substring2 = theName.substring(1); + + newProfileDetail.setFirstName(substring2); + newProfileDetail.setLastName(substring); + } else { + newProfileDetail.setFirstName(s[0]); + newProfileDetail.setLastName(s[s.length - 1]); + } + + membershipDto.setNumber(playerId); + membershipDto.setRefId(membershipRefId); + + String daylightLevelCode = ProfileTierEnums.fromIgtPMLevel(tierName); + + if (StringUtils.isNotEmpty(daylightLevelCode)) { + // TO'DO 暂时固定成这个Level,之后需要通过player的 tier 来确定它在daylight那边的level by Mauve 2026-07-10 + // 这个 TO'DO 可能已经完成了 by Mauve 2026-07-10 + membershipDto.setTypeCode("MGM"); + + membershipDto.setLevelCode(daylightLevelCode); + } + + newProfileDto.setDetails(newProfileDetail); + newProfileDto.setMemberships(List.of(membershipDto)); + newProfileDto.setTypeCode("PIND"); // 写死不需要改 + newProfileDto.setRefId(profileRefId); + newProfileDto.setMemRefId(membershipRefId); + newProfileDto.setMemberLevelCode(membershipDto.getLevelCode()); + newProfileDto.setMemberTypeCode(membershipDto.getTypeCode()); + + return newProfileDto; + } + + public static IndividualDTO buildNewProfileWithoutPlayerId( + String playerName, + String profileRefId + ) { + IndividualDTO newProfileDto = new IndividualDTO(); + IndividualDTO.IndividualDetailsDTO newProfileDetail = new IndividualDTO.IndividualDetailsDTO(); + + String[] s = playerName.split(" "); + + if (s.length == 1) { + String theName = s[0]; + String substring = theName.substring(0, 1); + String substring2 = theName.substring(1); + + newProfileDetail.setFirstName(substring2); + newProfileDetail.setLastName(substring); + } else { + newProfileDetail.setFirstName(s[0]); + newProfileDetail.setLastName(s[s.length - 1]); + } + + newProfileDto.setDetails(newProfileDetail); + newProfileDto.setTypeCode("PIND"); + newProfileDto.setRefId(profileRefId); + + return newProfileDto; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/PurchaseElementsWithInventoryItemsDTO.java b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/PurchaseElementsWithInventoryItemsDTO.java new file mode 100644 index 0000000..0324b6a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/PurchaseElementsWithInventoryItemsDTO.java @@ -0,0 +1,28 @@ +package com.mgm.mcrm.booking.dtos.daylight.requests.createReservation; + +import lombok.Data; + +import java.util.List; + +@Data +public class PurchaseElementsWithInventoryItemsDTO { + + private List purchaseElements; + + @Data + public static class PurchaseElementDTO { + + private String purchaseElementId; + private String dateAnchor; + private List breakdown; + + @Data + public static class PurchaseBreakdownDTO { + + private String from; + private String to; + private Integer guestCount; + private Integer quantity; + } + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/ReservationDTO.java b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/ReservationDTO.java new file mode 100644 index 0000000..ae391a2 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/ReservationDTO.java @@ -0,0 +1,110 @@ +package com.mgm.mcrm.booking.dtos.daylight.requests.createReservation; + +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Data; + +import java.util.List; + +@Data +public class ReservationDTO { + + @JSONField(name = "_refId") + private String refId; + private GuestDTO guest; + private String arrivalDate; + private String departureDate; + private AllocationDTO allocation; + private List breakdown; + private String guaranteeTypeId; + private String channelId; + private String sourceId; + private String eta; + private List accompanyingGuests; + private ReservationMembershipDTO membership; + private List preferences; + + @JSONField(name = "_flowControl") + private ReservationFlowControlDTO flowControl; + private Boolean noPost; + private String blockId; + private Boolean useProfileBillingRules; + private PurchaseElementsWithInventoryItemsDTO purchaseElementsWithInventoryItems; + + @JSONField(name = "_embedded") + private ReservationEmbeddedDTO embedded; + private List customFields; + + @Data + public static class GuestDTO { + + private String id; + } + + @Data + public static class AllocationDTO { + + private String roomTypeId; + } + + @Data + public static class BreakdownDTO { + + private String fromDate; + private String toDate; + private List guests; + private String marketSegmentId; + private RatePricingDetailsDTO ratePricingDetails; + + @Data + public static class GuestCountDTO { + + private String ageBucketId; + private Integer count; + } + + @Data + public static class RatePricingDetailsDTO { + + private String ratePlanId; + private String roomTypeToChargeId; + } + } + + @Data + public static class PreferenceDTO { + + private String id; + } + + @Data + public static class ReservationFlowControlDTO { + + private String upsertNotesStrategy; + private String externalIdsCollectionBehaviour; + private String preferencesCollectionBehaviour; + } + + + @Data + public static class ReservationEmbeddedDTO { + + private List notes; + + @Data + public static class NoteDTO { + + @JSONField(name = "_refId") + private String refId; + + private String typeCode; + private String content; + } + } + + @Data + public static class CustomFieldDTO { + + private String location; + private String value; + } +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/ReservationMembershipDTO.java b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/ReservationMembershipDTO.java new file mode 100644 index 0000000..08ba770 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/ReservationMembershipDTO.java @@ -0,0 +1,14 @@ +package com.mgm.mcrm.booking.dtos.daylight.requests.createReservation; + +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Data; + +@Data +public class ReservationMembershipDTO { + + private String id; + + @JSONField(name = "_refId") + private String refId; + private Boolean useDefaultMembership; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/ReservationRequestDTO.java b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/ReservationRequestDTO.java new file mode 100644 index 0000000..cbcc6b1 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/requests/createReservation/ReservationRequestDTO.java @@ -0,0 +1,50 @@ +package com.mgm.mcrm.booking.dtos.daylight.requests.createReservation; + +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Data; + +import java.util.List; + +@Data +public class ReservationRequestDTO { + + @JSONField(name = "_flowControl") + private FlowControlDTO flowControl; + + private IdentityDTO identity; + + private List externalIds; + + @JSONField(name = "_embedded") + private EmbeddedDTO embedded; + + private List reservations; + + private String cancellationReasonId; + + @Data + public static class FlowControlDTO { + + private String processId; + private Boolean upsertProfiles; + } + + @Data + public static class IdentityDTO { + + private ExternalIdDTO externalId; + } + + @Data + public static class ExternalIdDTO { + + private String systemId; + private String number; + } + + @Data + public static class EmbeddedDTO { + + private List individuals; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/daylight/responses/DistributionChannelResponse.java b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/responses/DistributionChannelResponse.java new file mode 100644 index 0000000..9a62ca1 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/responses/DistributionChannelResponse.java @@ -0,0 +1,11 @@ +package com.mgm.mcrm.booking.dtos.daylight.responses; + +import lombok.Data; + +@Data +public class DistributionChannelResponse { + + private String id; + + private String code; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/daylight/responses/GuaranteeTypeResponse.java b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/responses/GuaranteeTypeResponse.java new file mode 100644 index 0000000..2f0d4c5 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/daylight/responses/GuaranteeTypeResponse.java @@ -0,0 +1,11 @@ +package com.mgm.mcrm.booking.dtos.daylight.responses; + +import lombok.Data; + +@Data +public class GuaranteeTypeResponse { + + private String id; + + private String code; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CancelBookingIDPair.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CancelBookingIDPair.java new file mode 100644 index 0000000..58d0cdb --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CancelBookingIDPair.java @@ -0,0 +1,34 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + +@XStreamAlias("IDPair") +public class CancelBookingIDPair { + + @XStreamAlias("idType") + @XStreamAsAttribute() + private String idType; + + @XStreamAlias("operaId") + @XStreamAsAttribute() + private String operaId; + + public String getIdType() { + return idType; + } + + public void setIdType(String idType) { + this.idType = idType; + } + + public String getOperaId() { + return operaId; + } + + public void setOperaId(String operaId) { + this.operaId = operaId; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CancelBookingIDs.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CancelBookingIDs.java new file mode 100644 index 0000000..16244c4 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CancelBookingIDs.java @@ -0,0 +1,20 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("CancelBookingIDs") +public class CancelBookingIDs { + + + @XStreamAlias("IDPair") + private CancelBookingIDPair iDPair; + + public CancelBookingIDPair getiDPair() { + return iDPair; + } + + public void setiDPair(CancelBookingIDPair iDPair) { + this.iDPair = iDPair; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CancelBookingRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CancelBookingRequest.java new file mode 100644 index 0000000..0a9ed8d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CancelBookingRequest.java @@ -0,0 +1,72 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +public class CancelBookingRequest { + + private String transactionID; + private String timeStamp; + private StringBuffer requestString; + private String confirmationNo; + private String hotelCode; + + public CancelBookingRequest() { + } + + public StringBuffer getRequestString() { + String cancelCode = ""; + this.requestString = new StringBuffer(); + this.requestString.append(""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "+this.confirmationNo+""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(""); + + return this.requestString; + } + + public String getTransactionID() { + return transactionID; + } + + public void setTransactionID(String transactionID) { + this.transactionID = transactionID; + } + + public String getTimeStamp() { + return timeStamp; + } + + public void setTimeStamp(String timeStamp) { + this.timeStamp = timeStamp; + } + + + public String getHotelCode() { + return hotelCode; + } + + public void setHotelCode(String hotelCode) { + this.hotelCode = hotelCode; + } + + public String getConfirmationNo() { + return confirmationNo; + } + + public void setConfirmationNo(String confirmationNo) { + this.confirmationNo = confirmationNo; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CancelBookingResponse.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CancelBookingResponse.java new file mode 100644 index 0000000..630e37b --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CancelBookingResponse.java @@ -0,0 +1,35 @@ +package com.mgm.mcrm.booking.dtos.opera; +import java.io.Serializable; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("CancelBookingResponse") +public class CancelBookingResponse implements Serializable { + + + @XStreamAlias("Result") + private CancelBookingResult result; + + + + + public CancelBookingResponse() { + + } + + + public CancelBookingResult getResult() { + return result; + } + + + public void setResult(CancelBookingResult result) { + this.result = result; + } + + + + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CancelBookingResult.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CancelBookingResult.java new file mode 100644 index 0000000..4237dcf --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CancelBookingResult.java @@ -0,0 +1,55 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + +@XStreamAlias("Result") +public class CancelBookingResult { + + @XStreamAlias("resultStatusFlag") + @XStreamAsAttribute() + private String resultStatusFlag; + + @XStreamAlias("IDs") + private CancelBookingIDs iDs; + + @XStreamAlias("GDSError") + private String gDSError; + + @XStreamAlias("OperaErrorCode") + private String operaErrorCode; + + + public String getResultStatusFlag() { + return resultStatusFlag; + } + + public void setResultStatusFlag(String resultStatusFlag) { + this.resultStatusFlag = resultStatusFlag; + } + + public String getgDSError() { + return gDSError; + } + + public void setgDSError(String gDSError) { + this.gDSError = gDSError; + } + + public String getOperaErrorCode() { + return operaErrorCode; + } + + public void setOperaErrorCode(String operaErrorCode) { + this.operaErrorCode = operaErrorCode; + } + + public CancelBookingIDs getiDs() { + return iDs; + } + + public void setiDs(CancelBookingIDs iDs) { + this.iDs = iDs; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CombineShareRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CombineShareRequest.java new file mode 100644 index 0000000..1dc0633 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CombineShareRequest.java @@ -0,0 +1,89 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.mgm.mcrm.basesetting.property.models.CfgProperties; + +public class CombineShareRequest { + + private String transactionID; + private String timeStamp; + private CfgProperties property; + private StringBuffer requestString; + private String confirmationNo; + private List joinConfirmationNos; + + public CombineShareRequest() { + } + + public StringBuffer getRequestString() { + this.requestString = new StringBuffer(); + this.requestString.append(""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "+this.confirmationNo+""); + this.requestString.append(" 1"); + for(int i=0;i"); + this.requestString.append(" "+this.joinConfirmationNos.get(i)+""); + this.requestString.append(" 1"); + this.requestString.append(" "); + } + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(""); + + return this.requestString; + } + + public String getTransactionID() { + return transactionID; + } + + public void setTransactionID(String transactionID) { + this.transactionID = transactionID; + } + + public String getTimeStamp() { + return timeStamp; + } + + public void setTimeStamp(String timeStamp) { + this.timeStamp = timeStamp; + } + + public String getConfirmationNo() { + return confirmationNo; + } + + public void setConfirmationNo(String confirmationNo) { + this.confirmationNo = confirmationNo; + } + + public List getJoinConfirmationNos() { + return joinConfirmationNos; + } + + public void setJoinConfirmationNos(List joinConfirmationNos) { + this.joinConfirmationNos = joinConfirmationNos; + } + + public CfgProperties getProperty() { + return property; + } + + public void setProperty(CfgProperties property) { + this.property = property; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CombineShareResponse.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CombineShareResponse.java new file mode 100644 index 0000000..e29d693 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CombineShareResponse.java @@ -0,0 +1,31 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.io.Serializable; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("CombineShareResponse") +public class CombineShareResponse implements Serializable { + + + @XStreamAlias("Result") + private GuestRequestsResult result; + + + public CombineShareResponse() { + + } + + + public GuestRequestsResult getResult() { + return result; + } + + + public void setResult(GuestRequestsResult result) { + this.result = result; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingHotelReservation.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingHotelReservation.java new file mode 100644 index 0000000..25d565b --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingHotelReservation.java @@ -0,0 +1,41 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("HotelReservation") +public class CreateBookingHotelReservation { + + @XStreamAlias("UniqueIDList") + private CreateBookingUniqueIDList uniqueIDList; + + @XStreamAlias("ResGuests") + private CreateBookingResGuests resGuests; + + @XStreamAlias("RoomStays") + private CreateBookingRoomStays roomStays; + + public CreateBookingUniqueIDList getUniqueIDList() { + return uniqueIDList; + } + + public void setUniqueIDList(CreateBookingUniqueIDList uniqueIDList) { + this.uniqueIDList = uniqueIDList; + } + + public CreateBookingResGuests getResGuests() { + return resGuests; + } + + public void setResGuests(CreateBookingResGuests resGuests) { + this.resGuests = resGuests; + } + + public CreateBookingRoomStays getRoomStays() { + return roomStays; + } + + public void setRoomStays(CreateBookingRoomStays roomStays) { + this.roomStays = roomStays; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingProfile.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingProfile.java new file mode 100644 index 0000000..d0b1622 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingProfile.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("Profile") +public class CreateBookingProfile { + + @XStreamAlias("ProfileIDs") + private CreateBookingProfileIDs profileIDs; + + public CreateBookingProfileIDs getProfileIDs() { + return profileIDs; + } + + public void setProfileIDs(CreateBookingProfileIDs profileIDs) { + this.profileIDs = profileIDs; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingProfileIDs.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingProfileIDs.java new file mode 100644 index 0000000..19a64fa --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingProfileIDs.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("ProfileIDs") +public class CreateBookingProfileIDs { + + @XStreamAlias("UniqueID") + private String uniqueID; + + public String getUniqueID() { + return uniqueID; + } + + public void setUniqueID(String uniqueID) { + this.uniqueID = uniqueID; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingProfiles.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingProfiles.java new file mode 100644 index 0000000..c0546a8 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingProfiles.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("Profiles") +public class CreateBookingProfiles { + + @XStreamAlias("Profile") + private CreateBookingProfile profile; + + public CreateBookingProfile getProfile() { + return profile; + } + + public void setProfile(CreateBookingProfile profile) { + this.profile = profile; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRequest.java new file mode 100644 index 0000000..98f1a5e --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRequest.java @@ -0,0 +1,263 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.mgm.mcrm.booking.services.BookingService; +import org.apache.commons.lang3.StringUtils; + +import com.alibaba.fastjson.JSONObject; +import com.google.gson.Gson; + +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.common.utils.DateTimeUtil; +import com.mgm.mcrm.common.utils.LogUtil; + +public class CreateBookingRequest { + + private StringBuffer requestString; + private Bookings booking; + private String transactionID; + private String timeStamp; + private StringBuffer requestHeader; + private List specialRequests = null; + private Integer numberOfUnits=1; + private Integer numberOfAdults=1; + + public StringBuffer getRequestString() { + this.booking.setGuaranteeType("CGTD"); +// this.booking.setRatePlanCode("ITTEST8"); + String authorizer = this.booking.getChainCode()+this.booking.getCreatedBy(); + JSONObject memberObj = new JSONObject(); + Gson gson = new Gson(); + if(!StringUtils.isEmpty(booking.getMember())) { + memberObj = JSONObject.parseObject(booking.getMember()); + } + LogUtil.info(BookingService.class, + "[CreateBookingRequest] memberObj " + gson.toJson(memberObj)); + this.requestString = new StringBuffer(); + this.requestString.append(""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" 0) this.requestString.append(" numberOfUnits=\""+this.numberOfUnits +"\" "); + this.requestString.append( ">"); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "+DateTimeUtil.getDateByFormat(this.booking.getCheckinDate(), "yyyy-MM-dd")+""); + this.requestString.append(" "+DateTimeUtil.getDateByFormat(this.booking.getCheckoutDate(), "yyyy-MM-dd")+""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + if(specialRequests!=null && specialRequests.size()>0) { + this.requestString.append(" "); + for(int i=0;i"); + } + this.requestString.append(" "); + } + if(!StringUtils.isEmpty(this.booking.getItemCode())) { + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + } + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" = 5) this.booking.setEta(this.booking.getEta().substring(0, 5)+ ":00"); + this.requestString.append(" arrivalTime=\""+this.booking.getEta()+"\""); + } + this.requestString.append(">"); + this.requestString.append(" "); + this.requestString.append(" "); + if(this.booking.getOperaProfileId()!=null) { + this.requestString.append(" "); + this.requestString.append(" "+this.booking.getOperaProfileId()+""); + this.requestString.append(" "); +// this.requestString.append(" "); +// this.requestString.append(" "); +// this.requestString.append(" MGM"); +// this.requestString.append(" "+this.booking.getPlayerId()+""); +// this.requestString.append(" "); +// this.requestString.append(" "); + }else { + this.requestString.append(" "); + this.requestString.append(" "); + if(this.checkObjKey(memberObj,"salutation")) this.requestString.append(" "+memberObj.getString("salutation")+""); + if(this.booking.getMemberFirstName()!=null) this.requestString.append(" "+this.booking.getMemberFirstName()+""); + this.requestString.append(" "+this.booking.getMemberLastName()+""); + this.requestString.append(" "); + this.requestString.append(" "); + if(this.checkObjKey(memberObj,"country")||this.checkObjKey(memberObj,"state")) { + this.requestString.append(" "); + this.requestString.append(" "); + if(this.checkObjKey(memberObj,"country")) this.requestString.append(""+memberObj.getString("country")+""); + if(this.checkObjKey(memberObj,"state")) this.requestString.append(""+memberObj.getString("state")+""); + this.requestString.append(" "); + this.requestString.append(" "); + } + if(this.checkObjKey(memberObj,"playerPhone")) { + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "+memberObj.getString("playerPhone")+""); + this.requestString.append(" "); + this.requestString.append(" "); + } + } + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "+this.booking.getCreatedBy() +""); + this.requestString.append(" "); + if(this.booking.getApprovedId() != null) { + this.requestString.append(" "); + this.requestString.append(" APP"); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "+this.booking.getApprovedId() +""); + this.requestString.append(" "); + } + if(this.booking.getMiscCharge() != null) { + this.requestString.append(" "); + this.requestString.append(" "+this.booking.getMiscCharge() +""); + this.requestString.append(" "); + } +// if(this.booking.getApprovalReason()!=null) { +// this.requestString.append(" "); +// this.requestString.append(" "+this.booking.getApprovalReason() +""); +// this.requestString.append(" "); +// } + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(""); + + return this.requestString; + } + + + public String getTransactionID() { + return transactionID; + } + + public void setTransactionID(String transactionID) { + this.transactionID = transactionID; + } + + public String getTimeStamp() { + return timeStamp; + } + + public void setTimeStamp(String timeStamp) { + this.timeStamp = timeStamp; + } + + public StringBuffer getRequestHeader() { + return requestHeader; + } + + public void setRequestHeader(StringBuffer requestHeader) { + this.requestHeader = requestHeader; + } + + public void setRequestString(StringBuffer requestString) { + this.requestString = requestString; + } + + public List getSpecialRequests() { + return specialRequests; + } + + public void setSpecialRequests(List specialRequests) { + this.specialRequests = specialRequests; + } + + public Integer getNumberOfUnits() { + return numberOfUnits; + } + + public void setNumberOfUnits(Integer numberOfUnits) { + this.numberOfUnits = numberOfUnits; + } + + public Bookings getBooking() { + return booking; + } + + public void setBooking(Bookings booking) { + this.booking = booking; + } + + + public Integer getNumberOfAdults() { + return numberOfAdults; + } + + + public void setNumberOfAdults(Integer numberOfAdults) { + this.numberOfAdults = numberOfAdults; + } + + public boolean checkObjKey(JSONObject obj,String key) { + boolean check = false; + if(obj.containsKey(key)) { + if(obj.get(key)!=null) { + if(!obj.getString(key).isEmpty()) { + check = true; + } + } + } + return check; + } + + public String getDOB(String dob) { + String getDob = dob; + String[] dobArr = StringUtils.split(getDob,"T"); + if(dobArr.length>1) { + getDob = dobArr[0]; + } + return getDob; + + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingResGuest.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingResGuest.java new file mode 100644 index 0000000..c6364e7 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingResGuest.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("ResGuest") +public class CreateBookingResGuest { + + @XStreamAlias("Profiles") + private CreateBookingProfiles profiles; + + public CreateBookingProfiles getProfiles() { + return profiles; + } + + public void setProfiles(CreateBookingProfiles profiles) { + this.profiles = profiles; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingResGuests.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingResGuests.java new file mode 100644 index 0000000..06f6acf --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingResGuests.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("ResGuests") +public class CreateBookingResGuests { + + @XStreamAlias("ResGuest") + private CreateBookingResGuest resGuest; + + public CreateBookingResGuest getResGuest() { + return resGuest; + } + + public void setResGuest(CreateBookingResGuest resGuest) { + this.resGuest = resGuest; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingResponse.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingResponse.java new file mode 100644 index 0000000..666fa4a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingResponse.java @@ -0,0 +1,43 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.io.Serializable; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("CreateBookingResponse") +public class CreateBookingResponse implements Serializable { + + + @XStreamAlias("HotelReservation") + private CreateBookingHotelReservation hotelReservation; + + @XStreamAlias("Result") + private GuestRequestsResult result; + + + public CreateBookingResponse() { + + } + + + public CreateBookingHotelReservation getHotelReservation() { + return hotelReservation; + } + + + public void setHotelReservation(CreateBookingHotelReservation hotelReservation) { + this.hotelReservation = hotelReservation; + } + + public GuestRequestsResult getResult() { + return result; + } + + + public void setResult(GuestRequestsResult result) { + this.result = result; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRoomStay.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRoomStay.java new file mode 100644 index 0000000..a36c237 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRoomStay.java @@ -0,0 +1,33 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("RoomStay") +public class CreateBookingRoomStay { + + @XStreamAlias("RoomTypes") + private CreateBookingRoomTypes roomTypes; + + @XStreamAlias("Total") + private String total; + + + public CreateBookingRoomTypes getRoomTypes() { + return roomTypes; + } + + public void setRoomTypes(CreateBookingRoomTypes roomTypes) { + this.roomTypes = roomTypes; + } + + public String getTotal() { + return total; + } + + public void setTotal(String total) { + this.total = total; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRoomStays.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRoomStays.java new file mode 100644 index 0000000..b6a6a09 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRoomStays.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("RoomStays") +public class CreateBookingRoomStays { + + @XStreamAlias("RoomStay") + private CreateBookingRoomStay roomStay; + + public CreateBookingRoomStay getRoomStay() { + return roomStay; + } + + public void setRoomStay(CreateBookingRoomStay roomStay) { + this.roomStay = roomStay; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRoomType.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRoomType.java new file mode 100644 index 0000000..59de35d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRoomType.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("RoomType") +public class CreateBookingRoomType { + + @XStreamAlias("RoomTypeDescription") + private CreateBookingRoomTypeDescription roomTypeDescription; + + public CreateBookingRoomTypeDescription getRoomTypeDescription() { + return roomTypeDescription; + } + + public void setRoomTypeDescription(CreateBookingRoomTypeDescription roomTypeDescription) { + this.roomTypeDescription = roomTypeDescription; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRoomTypeDescription.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRoomTypeDescription.java new file mode 100644 index 0000000..6decf68 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRoomTypeDescription.java @@ -0,0 +1,22 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("RoomTypeDescription") +public class CreateBookingRoomTypeDescription { + + @XStreamAlias("Text") + private String text; + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRoomTypes.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRoomTypes.java new file mode 100644 index 0000000..c2581a8 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingRoomTypes.java @@ -0,0 +1,18 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("RoomTypes") +public class CreateBookingRoomTypes { + + @XStreamAlias("RoomType") + private CreateBookingRoomType roomType; + + public CreateBookingRoomType getRoomType() { + return roomType; + } + + public void setRoomType(CreateBookingRoomType roomType) { + this.roomType = roomType; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingUniqueIDList.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingUniqueIDList.java new file mode 100644 index 0000000..c856de5 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/CreateBookingUniqueIDList.java @@ -0,0 +1,22 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("UniqueIDList") +public class CreateBookingUniqueIDList { + + @XStreamImplicit(itemFieldName="UniqueID") + private List listUniqueID; + + public List getListUniqueID() { + return listUniqueID; + } + + public void setListUniqueID(List listUniqueID) { + this.listUniqueID = listUniqueID; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAdditionalDetail.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAdditionalDetail.java new file mode 100644 index 0000000..0e536e4 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAdditionalDetail.java @@ -0,0 +1,23 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("AdditionalDetail") +public class FetchBookingAdditionalDetail { + + @XStreamAlias("AdditionalDetailDescription") + private String text; + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAdditionalDetailDescription.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAdditionalDetailDescription.java new file mode 100644 index 0000000..e7bd8c4 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAdditionalDetailDescription.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("AdditionalDetailDescription") +public class FetchBookingAdditionalDetailDescription { + + @XStreamAlias("Text") + private String text; + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAdditionalDetails.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAdditionalDetails.java new file mode 100644 index 0000000..54f7cc1 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAdditionalDetails.java @@ -0,0 +1,22 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("AdditionalDetails") +public class FetchBookingAdditionalDetails { + + @XStreamImplicit(itemFieldName="AdditionalDetail") + private List listAdditionalDetail; + + public List getListAdditionalDetail() { + return listAdditionalDetail; + } + + public void setListAdditionalDetail(List listAdditionalDetail) { + this.listAdditionalDetail = listAdditionalDetail; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAddresses.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAddresses.java new file mode 100644 index 0000000..e68d479 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAddresses.java @@ -0,0 +1,18 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("Addresses") +public class FetchBookingAddresses { + + @XStreamAlias("NameAddress") + private FetchBookingNameAddress nameAddress; + + public FetchBookingNameAddress getNameAddress() { + return nameAddress; + } + + public void setNameAddress(FetchBookingNameAddress nameAddress) { + this.nameAddress = nameAddress; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAllowance.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAllowance.java new file mode 100644 index 0000000..d302034 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAllowance.java @@ -0,0 +1,45 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; + +@XStreamAlias("Allowance") +@XStreamConverter(FetchBookingAllowanceConvert.class) +public class FetchBookingAllowance { + + @XStreamAsAttribute + @XStreamAlias("currencyCode") + private String currencyCode; + + @XStreamAsAttribute + @XStreamAlias("decimals") + private String decimals; + + private String totalValue; + + public String getCurrencyCode() { + return currencyCode; + } + + public void setCurrencyCode(String currencyCode) { + this.currencyCode = currencyCode; + } + + public String getDecimals() { + return decimals; + } + + public void setDecimals(String decimals) { + this.decimals = decimals; + } + + public String getTotalValue() { + return totalValue; + } + + public void setTotalValue(String totalValue) { + this.totalValue = totalValue; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAllowanceConvert.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAllowanceConvert.java new file mode 100644 index 0000000..3c5f8dd --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAllowanceConvert.java @@ -0,0 +1,39 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +public class FetchBookingAllowanceConvert implements Converter { + //转换条件 + @Override + public boolean canConvert(Class type) { + return type.equals(FetchBookingAllowance.class); + } + /** + * 将java对象转为xml时使用 + */ + @Override + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + FetchBookingAllowance base = (FetchBookingAllowance) source; + writer.addAttribute("currencyCode", base.getCurrencyCode()); + writer.addAttribute("decimals", base.getDecimals()); + writer.setValue(base.getTotalValue()); + } + /** + * 将xml转为java对象使用 + */ + @Override + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + // 在解析order元素时,先创建一个Order对象 + FetchBookingAllowance base = new FetchBookingAllowance(); + // 将order元素的name属性设置为Order对象的name属性值 + base.setCurrencyCode(reader.getAttribute("currencyCode")); + base.setDecimals(reader.getAttribute("decimals")); + // 将order元素的txt值设置为Order对象的value值 + base.setTotalValue(reader.getValue()); + return base; + } +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAmount.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAmount.java new file mode 100644 index 0000000..93373fd --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAmount.java @@ -0,0 +1,44 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; + +@XStreamAlias("Amount") +@XStreamConverter(FetchBookingAmountConvert.class) +public class FetchBookingAmount { + + @XStreamAsAttribute + @XStreamAlias("currencyCode") + private String currencyCode; + + @XStreamAsAttribute + @XStreamAlias("decimals") + private String decimals; + + private String thisValue; + + public String getCurrencyCode() { + return currencyCode; + } + + public void setCurrencyCode(String currencyCode) { + this.currencyCode = currencyCode; + } + + public String getDecimals() { + return decimals; + } + + public void setDecimals(String decimals) { + this.decimals = decimals; + } + + public String getThisValue() { + return thisValue; + } + + public void setThisValue(String thisValue) { + this.thisValue = thisValue; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAmountConvert.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAmountConvert.java new file mode 100644 index 0000000..eebc150 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingAmountConvert.java @@ -0,0 +1,39 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +public class FetchBookingAmountConvert implements Converter { + //转换条件 + @Override + public boolean canConvert(Class type) { + return type.equals(FetchBookingAmount.class); + } + /** + * 将java对象转为xml时使用 + */ + @Override + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + FetchBookingAmount base = (FetchBookingAmount) source; + writer.addAttribute("currencyCode", base.getCurrencyCode()); + writer.addAttribute("decimals", base.getDecimals()); + writer.setValue(base.getThisValue()); + } + /** + * 将xml转为java对象使用 + */ + @Override + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + // 在解析order元素时,先创建一个Order对象 + FetchBookingAmount base = new FetchBookingAmount(); + // 将order元素的name属性设置为Order对象的name属性值 + base.setCurrencyCode(reader.getAttribute("currencyCode")); + base.setDecimals(reader.getAttribute("decimals")); + // 将order元素的txt值设置为Order对象的value值 + base.setThisValue(reader.getValue()); + return base; + } +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingArrivalTransport.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingArrivalTransport.java new file mode 100644 index 0000000..efc59b3 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingArrivalTransport.java @@ -0,0 +1,62 @@ +package com.mgm.mcrm.booking.dtos.opera; +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("ArrivalTransport") +public class FetchBookingArrivalTransport { + + @XStreamAsAttribute + @XStreamAlias("time") + private String time; + + @XStreamAsAttribute + @XStreamAlias("type") + private String type; + + @XStreamAsAttribute + @XStreamAlias("carrierCode") + private String carrierCode; + + @XStreamAsAttribute + @XStreamAlias("locationCode") + private String locationCode; + + public String getTime() { + return time; + } + + public void setTime(String time) { + this.time = time; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getCarrierCode() { + return carrierCode; + } + + public void setCarrierCode(String carrierCode) { + this.carrierCode = carrierCode; + } + + public String getLocationCode() { + return locationCode; + } + + public void setLocationCode(String locationCode) { + this.locationCode = locationCode; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingBase.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingBase.java new file mode 100644 index 0000000..597ee75 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingBase.java @@ -0,0 +1,46 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; + +@XStreamAlias("Base") +@XStreamConverter(FetchBookingBaseConvert.class) +public class FetchBookingBase { + + @XStreamAsAttribute + @XStreamAlias("currencyCode") + private String currencyCode; + + @XStreamAsAttribute + @XStreamAlias("decimals") + private String decimals; + + private String baseValue; + + public String getCurrencyCode() { + return currencyCode; + } + + public void setCurrencyCode(String currencyCode) { + this.currencyCode = currencyCode; + } + + public String getDecimals() { + return decimals; + } + + public void setDecimals(String decimals) { + this.decimals = decimals; + } + + public String getBaseValue() { + return baseValue; + } + + public void setBaseValue(String baseValue) { + this.baseValue = baseValue; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingBaseConvert.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingBaseConvert.java new file mode 100644 index 0000000..fc49869 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingBaseConvert.java @@ -0,0 +1,39 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +public class FetchBookingBaseConvert implements Converter { + //转换条件 + @Override + public boolean canConvert(Class type) { + return type.equals(FutureBookingSummaryBase.class); + } + /** + * 将java对象转为xml时使用 + */ + @Override + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + FetchBookingBase base = (FetchBookingBase) source; + writer.addAttribute("currencyCode", base.getCurrencyCode()); + writer.addAttribute("decimals", base.getDecimals()); + writer.setValue(base.getBaseValue()); + } + /** + * 将xml转为java对象使用 + */ + @Override + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + // 在解析order元素时,先创建一个Order对象 + FetchBookingBase base = new FetchBookingBase(); + // 将order元素的name属性设置为Order对象的name属性值 + base.setCurrencyCode(reader.getAttribute("currencyCode")); + base.setDecimals(reader.getAttribute("decimals")); + // 将order元素的txt值设置为Order对象的value值 + base.setBaseValue(reader.getValue()); + return base; + } +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCancelTerm.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCancelTerm.java new file mode 100644 index 0000000..ef8eb1a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCancelTerm.java @@ -0,0 +1,50 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("CancelTerm") +public class FetchBookingCancelTerm { + + @XStreamAsAttribute + @XStreamAlias("cancelType") + private String cancelType; + + @XStreamAsAttribute + @XStreamAlias("cancelNumber") + private String cancelNumber; + + @XStreamAsAttribute + @XStreamAlias("cancelDate") + private String cancelDate; + + public String getCancelType() { + return cancelType; + } + + public void setCancelType(String cancelType) { + this.cancelType = cancelType; + } + + public String getCancelNumber() { + return cancelNumber; + } + + public void setCancelNumber(String cancelNumber) { + this.cancelNumber = cancelNumber; + } + + public String getCancelDate() { + return cancelDate; + } + + public void setCancelDate(String cancelDate) { + this.cancelDate = cancelDate; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCharges.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCharges.java new file mode 100644 index 0000000..72c2a2b --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCharges.java @@ -0,0 +1,59 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + +@XStreamAlias("Charges") +public class FetchBookingCharges { + + @XStreamAsAttribute + @XStreamAlias("Description") + private String description; + + @XStreamAlias("Amount") + private FetchBookingAmount amount; + + @XStreamAsAttribute + @XStreamAlias("CodeType") + private String codeType; + + @XStreamAsAttribute + @XStreamAlias("Code") + private String code; + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public FetchBookingAmount getAmount() { + return amount; + } + + public void setAmount(FetchBookingAmount amount) { + this.amount = amount; + } + + public String getCodeType() { + return codeType; + } + + public void setCodeType(String codeType) { + this.codeType = codeType; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingChargesForPostingDate.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingChargesForPostingDate.java new file mode 100644 index 0000000..d7f447c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingChargesForPostingDate.java @@ -0,0 +1,44 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + +@XStreamAlias("ChargesForPostingDate") +public class FetchBookingChargesForPostingDate { + + @XStreamAsAttribute + @XStreamAlias("PostingDate") + private String PostingDate; + + @XStreamAlias("RoomRateAndPackages") + private FetchBookingRoomRateAndPackages roomRateAndPackages; + + @XStreamAlias("TaxesAndFees") + private FetchBookingTaxesAndFees taxesAndFees; + + public String getPostingDate() { + return PostingDate; + } + + public void setPostingDate(String postingDate) { + PostingDate = postingDate; + } + + public FetchBookingRoomRateAndPackages getRoomRateAndPackages() { + return roomRateAndPackages; + } + + public void setRoomRateAndPackages(FetchBookingRoomRateAndPackages roomRateAndPackages) { + this.roomRateAndPackages = roomRateAndPackages; + } + + public FetchBookingTaxesAndFees getTaxesAndFees() { + return taxesAndFees; + } + + public void setTaxesAndFees(FetchBookingTaxesAndFees taxesAndFees) { + this.taxesAndFees = taxesAndFees; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingComment.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingComment.java new file mode 100644 index 0000000..7ebd8a8 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingComment.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("Comment") +public class FetchBookingComment { + + @XStreamAlias("Text") + private String text; + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingComments.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingComments.java new file mode 100644 index 0000000..e3487ed --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingComments.java @@ -0,0 +1,22 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("Comments") +public class FetchBookingComments { + + @XStreamImplicit(itemFieldName="Comment") + private List comment; + + public List getComment() { + return comment; + } + + public void setComment(List comment) { + this.comment = comment; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCompany.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCompany.java new file mode 100644 index 0000000..1d118f3 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCompany.java @@ -0,0 +1,46 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("Company") +public class FetchBookingCompany { + + @XStreamAlias("CompanyName") + private String companyName; + + @XStreamAlias("CompanyType") + private String companyType; + + @XStreamAlias("CompanyID") + private String companyID; + + public String getCompanyName() { + return companyName; + } + + public void setCompanyName(String companyName) { + this.companyName = companyName; + } + + public String getCompanyType() { + return companyType; + } + + public void setCompanyType(String companyType) { + this.companyType = companyType; + } + + public String getCompanyID() { + return companyID; + } + + public void setCompanyID(String companyID) { + this.companyID = companyID; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCurrentBalance.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCurrentBalance.java new file mode 100644 index 0000000..8eb15a0 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCurrentBalance.java @@ -0,0 +1,45 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; + +@XStreamAlias("CurrentBalance") +@XStreamConverter(FetchBookingCurrentBalanceConvert.class) +public class FetchBookingCurrentBalance { + + @XStreamAsAttribute + @XStreamAlias("currencyCode") + private String currencyCode; + + @XStreamAsAttribute + @XStreamAlias("decimals") + private String decimals; + + private String totalValue; + + public String getCurrencyCode() { + return currencyCode; + } + + public void setCurrencyCode(String currencyCode) { + this.currencyCode = currencyCode; + } + + public String getDecimals() { + return decimals; + } + + public void setDecimals(String decimals) { + this.decimals = decimals; + } + + public String getTotalValue() { + return totalValue; + } + + public void setTotalValue(String totalValue) { + this.totalValue = totalValue; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCurrentBalanceConvert.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCurrentBalanceConvert.java new file mode 100644 index 0000000..7343c4b --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCurrentBalanceConvert.java @@ -0,0 +1,39 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +public class FetchBookingCurrentBalanceConvert implements Converter { + //转换条件 + @Override + public boolean canConvert(Class type) { + return type.equals(FetchBookingCurrentBalance.class); + } + /** + * 将java对象转为xml时使用 + */ + @Override + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + FetchBookingCurrentBalance base = (FetchBookingCurrentBalance) source; + writer.addAttribute("currencyCode", base.getCurrencyCode()); + writer.addAttribute("decimals", base.getDecimals()); + writer.setValue(base.getTotalValue()); + } + /** + * 将xml转为java对象使用 + */ + @Override + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + // 在解析order元素时,先创建一个Order对象 + FetchBookingCurrentBalance base = new FetchBookingCurrentBalance(); + // 将order元素的name属性设置为Order对象的name属性值 + base.setCurrencyCode(reader.getAttribute("currencyCode")); + base.setDecimals(reader.getAttribute("decimals")); + // 将order元素的txt值设置为Order对象的value值 + base.setTotalValue(reader.getValue()); + return base; + } +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCustomer.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCustomer.java new file mode 100644 index 0000000..b3a50ac --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingCustomer.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("Customer") +public class FetchBookingCustomer { + + @XStreamAlias("PersonName") + private FetchBookingPersonName personName; + + public FetchBookingPersonName getPersonName() { + return personName; + } + + public void setPersonName(FetchBookingPersonName personName) { + this.personName = personName; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepartureTransport.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepartureTransport.java new file mode 100644 index 0000000..aa3c01c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepartureTransport.java @@ -0,0 +1,62 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("DepartureTransport") +public class FetchBookingDepartureTransport { + + @XStreamAsAttribute + @XStreamAlias("time") + private String time; + + @XStreamAsAttribute + @XStreamAlias("type") + private String type; + + @XStreamAsAttribute + @XStreamAlias("carrierCode") + private String carrierCode; + + @XStreamAsAttribute + @XStreamAlias("locationCode") + private String locationCode; + + public String getTime() { + return time; + } + + public void setTime(String time) { + this.time = time; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getCarrierCode() { + return carrierCode; + } + + public void setCarrierCode(String carrierCode) { + this.carrierCode = carrierCode; + } + + public String getLocationCode() { + return locationCode; + } + + public void setLocationCode(String locationCode) { + this.locationCode = locationCode; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepositAmount.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepositAmount.java new file mode 100644 index 0000000..d221e03 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepositAmount.java @@ -0,0 +1,44 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; + +@XStreamAlias("DepositAmount") +@XStreamConverter(FetchBookingDepositAmountConvert.class) +public class FetchBookingDepositAmount { + + @XStreamAsAttribute + @XStreamAlias("currencyCode") + private String currencyCode; + + @XStreamAsAttribute + @XStreamAlias("decimals") + private String decimals; + + private String thisValue; + + public String getCurrencyCode() { + return currencyCode; + } + + public void setCurrencyCode(String currencyCode) { + this.currencyCode = currencyCode; + } + + public String getDecimals() { + return decimals; + } + + public void setDecimals(String decimals) { + this.decimals = decimals; + } + + public String getThisValue() { + return thisValue; + } + + public void setThisValue(String thisValue) { + this.thisValue = thisValue; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepositAmountConvert.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepositAmountConvert.java new file mode 100644 index 0000000..f73c58f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepositAmountConvert.java @@ -0,0 +1,39 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +public class FetchBookingDepositAmountConvert implements Converter { + //转换条件 + @Override + public boolean canConvert(Class type) { + return type.equals(FetchBookingDepositAmount.class); + } + /** + * 将java对象转为xml时使用 + */ + @Override + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + FetchBookingDepositAmount base = (FetchBookingDepositAmount) source; + writer.addAttribute("currencyCode", base.getCurrencyCode()); + writer.addAttribute("decimals", base.getDecimals()); + writer.setValue(base.getThisValue()); + } + /** + * 将xml转为java对象使用 + */ + @Override + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + // 在解析order元素时,先创建一个Order对象 + FetchBookingDepositAmount base = new FetchBookingDepositAmount(); + // 将order元素的name属性设置为Order对象的name属性值 + base.setCurrencyCode(reader.getAttribute("currencyCode")); + base.setDecimals(reader.getAttribute("decimals")); + // 将order元素的txt值设置为Order对象的value值 + base.setThisValue(reader.getValue()); + return base; + } +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepositDueAmount.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepositDueAmount.java new file mode 100644 index 0000000..a3b9a94 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepositDueAmount.java @@ -0,0 +1,44 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; + +@XStreamAlias("DepositDueAmount") +@XStreamConverter(FetchBookingDepositDueAmountConvert.class) +public class FetchBookingDepositDueAmount { + + @XStreamAsAttribute + @XStreamAlias("currencyCode") + private String currencyCode; + + @XStreamAsAttribute + @XStreamAlias("decimals") + private String decimals; + + private String thisValue; + + public String getCurrencyCode() { + return currencyCode; + } + + public void setCurrencyCode(String currencyCode) { + this.currencyCode = currencyCode; + } + + public String getDecimals() { + return decimals; + } + + public void setDecimals(String decimals) { + this.decimals = decimals; + } + + public String getThisValue() { + return thisValue; + } + + public void setThisValue(String thisValue) { + this.thisValue = thisValue; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepositDueAmountConvert.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepositDueAmountConvert.java new file mode 100644 index 0000000..b015e88 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepositDueAmountConvert.java @@ -0,0 +1,39 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +public class FetchBookingDepositDueAmountConvert implements Converter { + //转换条件 + @Override + public boolean canConvert(Class type) { + return type.equals(FetchBookingDepositDueAmount.class); + } + /** + * 将java对象转为xml时使用 + */ + @Override + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + FetchBookingDepositDueAmount base = (FetchBookingDepositDueAmount) source; + writer.addAttribute("currencyCode", base.getCurrencyCode()); + writer.addAttribute("decimals", base.getDecimals()); + writer.setValue(base.getThisValue()); + } + /** + * 将xml转为java对象使用 + */ + @Override + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + // 在解析order元素时,先创建一个Order对象 + FetchBookingDepositDueAmount base = new FetchBookingDepositDueAmount(); + // 将order元素的name属性设置为Order对象的name属性值 + base.setCurrencyCode(reader.getAttribute("currencyCode")); + base.setDecimals(reader.getAttribute("decimals")); + // 将order元素的txt值设置为Order对象的value值 + base.setThisValue(reader.getValue()); + return base; + } +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepositRequired.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepositRequired.java new file mode 100644 index 0000000..5841808 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDepositRequired.java @@ -0,0 +1,31 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("DepositRequired") +public class FetchBookingDepositRequired { + + @XStreamAlias("DepositAmount") + private FetchBookingDepositAmount depositAmount; + + @XStreamAlias("DepositDueAmount") + private FetchBookingDepositDueAmount depositDueAmount; + + public FetchBookingDepositAmount getDepositAmount() { + return depositAmount; + } + + public void setDepositAmount(FetchBookingDepositAmount depositAmount) { + this.depositAmount = depositAmount; + } + + public FetchBookingDepositDueAmount getDepositDueAmount() { + return depositDueAmount; + } + + public void setDepositDueAmount(FetchBookingDepositDueAmount depositDueAmount) { + this.depositDueAmount = depositDueAmount; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDescription.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDescription.java new file mode 100644 index 0000000..7b17ab8 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingDescription.java @@ -0,0 +1,20 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("Description") +public class FetchBookingDescription { + + @XStreamAlias("Text") + private FetchBookingText text; + + public FetchBookingText getText() { + return text; + } + + public void setText(FetchBookingText text) { + this.text = text; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingExpectedCharges.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingExpectedCharges.java new file mode 100644 index 0000000..08c1133 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingExpectedCharges.java @@ -0,0 +1,72 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("ExpectedCharges") +public class FetchBookingExpectedCharges { + + @XStreamAsAttribute + @XStreamAlias("TotalRoomRateAndPackages") + private Double totalRoomRateAndPackages; + + @XStreamAsAttribute + @XStreamAlias("TotalTaxesAndFees") + private Double totalTaxesAndFees; + + @XStreamAsAttribute + @XStreamAlias("TaxInclusive") + private boolean TaxInclusive; + + @XStreamAsAttribute + @XStreamAlias("decimals") + private Double decimals; + + @XStreamImplicit(itemFieldName="ChargesForPostingDate") + private List chargesForPostingDate; + + public List getChargesForPostingDate() { + return chargesForPostingDate; + } + + public void setChargesForPostingDate(List chargesForPostingDate) { + this.chargesForPostingDate = chargesForPostingDate; + } + + public Double getTotalRoomRateAndPackages() { + return totalRoomRateAndPackages; + } + + public void setTotalRoomRateAndPackages(Double totalRoomRateAndPackages) { + this.totalRoomRateAndPackages = totalRoomRateAndPackages; + } + + public Double getTotalTaxesAndFees() { + return totalTaxesAndFees; + } + + public void setTotalTaxesAndFees(Double totalTaxesAndFees) { + this.totalTaxesAndFees = totalTaxesAndFees; + } + + public boolean isTaxInclusive() { + return TaxInclusive; + } + + public void setTaxInclusive(boolean taxInclusive) { + TaxInclusive = taxInclusive; + } + + public Double getDecimals() { + return decimals; + } + + public void setDecimals(Double decimals) { + this.decimals = decimals; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingGuarantee.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingGuarantee.java new file mode 100644 index 0000000..fd9e436 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingGuarantee.java @@ -0,0 +1,26 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("Guarantee") +public class FetchBookingGuarantee { + + @XStreamAsAttribute + @XStreamAlias("guaranteeType") + private String guaranteeType; + + public String getGuaranteeType() { + return guaranteeType; + } + + public void setGuaranteeType(String guaranteeType) { + this.guaranteeType = guaranteeType; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingGuestCount.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingGuestCount.java new file mode 100644 index 0000000..e012818 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingGuestCount.java @@ -0,0 +1,37 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("GuestCount") +public class FetchBookingGuestCount { + + @XStreamAsAttribute + @XStreamAlias("ageQualifyingCode") + private String ageQualifyingCode; + + @XStreamAsAttribute + @XStreamAlias("count") + private int count; + + public String getAgeQualifyingCode() { + return ageQualifyingCode; + } + + public void setAgeQualifyingCode(String ageQualifyingCode) { + this.ageQualifyingCode = ageQualifyingCode; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingGuestCounts.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingGuestCounts.java new file mode 100644 index 0000000..4c76fb5 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingGuestCounts.java @@ -0,0 +1,22 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("GuestCounts") +public class FetchBookingGuestCounts { + + @XStreamImplicit(itemFieldName="GuestCount") + private List guestCount; + + public List getGuestCount() { + return guestCount; + } + + public void setGuestCount(List guestCount) { + this.guestCount = guestCount; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingHotelReference.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingHotelReference.java new file mode 100644 index 0000000..75f5020 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingHotelReference.java @@ -0,0 +1,46 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; + +@XStreamAlias("HotelReference") +@XStreamConverter(FetchBookingHotelReferenceConvert.class) +public class FetchBookingHotelReference { + + @XStreamAsAttribute + @XStreamAlias("chainCode") + private String chainCode; + + @XStreamAsAttribute + @XStreamAlias("hotelCode") + private String hotelCode; + + private String thisValue; + + public String getChainCode() { + return chainCode; + } + + public void setChainCode(String chainCode) { + this.chainCode = chainCode; + } + + public String getHotelCode() { + return hotelCode; + } + + public void setHotelCode(String hotelCode) { + this.hotelCode = hotelCode; + } + + public String getThisValue() { + return thisValue; + } + + public void setThisValue(String thisValue) { + this.thisValue = thisValue; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingHotelReferenceConvert.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingHotelReferenceConvert.java new file mode 100644 index 0000000..82f1846 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingHotelReferenceConvert.java @@ -0,0 +1,39 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +public class FetchBookingHotelReferenceConvert implements Converter { + //转换条件 + @Override + public boolean canConvert(Class type) { + return type.equals(FetchBookingHotelReference.class); + } + /** + * 将java对象转为xml时使用 + */ + @Override + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + FetchBookingHotelReference base = (FetchBookingHotelReference) source; + writer.addAttribute("chainCode", base.getChainCode()); + writer.addAttribute("hotelCode", base.getHotelCode()); + writer.setValue(base.getThisValue()); + } + /** + * 将xml转为java对象使用 + */ + @Override + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + // 在解析order元素时,先创建一个Order对象 + FetchBookingHotelReference base = new FetchBookingHotelReference(); + // 将order元素的name属性设置为Order对象的name属性值 + base.setChainCode(reader.getAttribute("chainCode")); + base.setHotelCode(reader.getAttribute("hotelCode")); + // 将order元素的txt值设置为Order对象的value值 + base.setThisValue(reader.getValue()); + return base; + } +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingHotelReservation.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingHotelReservation.java new file mode 100644 index 0000000..1c50de2 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingHotelReservation.java @@ -0,0 +1,401 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + +@XStreamAlias("HotelReservation") +public class FetchBookingHotelReservation { + + @XStreamAsAttribute + @XStreamAlias("reservationStatus") + private String reservationStatus; + + @XStreamAsAttribute + @XStreamAlias("marketSegment") + private String marketSegment; + + @XStreamAsAttribute + @XStreamAlias("sourceCode") + private String sourceCode; + + @XStreamAsAttribute + @XStreamAlias("originCode") + private String originCode; + + @XStreamAsAttribute + @XStreamAlias("onBehalfFlag") + private boolean onBehalfFlag; + + @XStreamAsAttribute + @XStreamAlias("redemReservationFlag") + private boolean redemReservationFlag; + + @XStreamAsAttribute + @XStreamAlias("group") + private String group; + + @XStreamAsAttribute + @XStreamAlias("OptIn") + private boolean optIn; + + @XStreamAsAttribute + @XStreamAlias("OptInComplete") + private boolean optInComplete; + + @XStreamAsAttribute + @XStreamAlias("financialTransactionExists") + private boolean financialTransactionExists; + + @XStreamAsAttribute + @XStreamAlias("printRate") + private boolean printRate; + + @XStreamAsAttribute + @XStreamAlias("referralYN") + private String referralYN; + + @XStreamAsAttribute + @XStreamAlias("noPost") + private boolean noPost; + + @XStreamAsAttribute + @XStreamAlias("commentsExists") + private boolean commentsExists; + + @XStreamAsAttribute + @XStreamAlias("commentsCount") + private int commentsCount; + + @XStreamAsAttribute + @XStreamAlias("tracesExists") + private boolean tracesExists; + + @XStreamAsAttribute + @XStreamAlias("specialsExists") + private boolean specialsExists; + + @XStreamAsAttribute + @XStreamAlias("roomPreferenceExists") + private boolean roomPreferenceExists; + + @XStreamAsAttribute + @XStreamAlias("shareExists") + private boolean shareExists; + + @XStreamAsAttribute + @XStreamAlias("queueExists") + private boolean queueExists; + + @XStreamAsAttribute + @XStreamAlias("alertExists") + private boolean alertExists; + + @XStreamAsAttribute + @XStreamAlias("messageExists") + private boolean messageExists; + + @XStreamAsAttribute + @XStreamAlias("checkOutTime") + private String checkOutTime; + + @XStreamAsAttribute + @XStreamAlias("checkInTime") + private String checkInTime; + + @XStreamAsAttribute + @XStreamAlias("returningGuest") + private boolean returningGuest; + + @XStreamAsAttribute + @XStreamAlias("computedReservationStatus") + private String computedReservationStatus; + + @XStreamAlias("UniqueIDList") + private FetchBookingUniqueIDList uniqueIDList; + + @XStreamAlias("RoomStays") + private FetchBookingRoomStays roomStays; + + @XStreamAlias("ResGuests") + private FetchBookingResGuests resGuests; + + @XStreamAlias("ReservationHistory") + private FetchBookingReservationHistory reservationHistory; + + @XStreamAlias("UserDefinedValues") + private FetchBookingUserDefinedValues userDefinedValues; + + @XStreamAlias("ReservationPayments") + private FetchBookingReservationPayments reservationPayments; + + @XStreamAlias("ShareReservations") + private FetchBookingShareReservations shareReservations; + + + public String getReservationStatus() { + return reservationStatus; + } + + public void setReservationStatus(String reservationStatus) { + this.reservationStatus = reservationStatus; + } + + public String getMarketSegment() { + return marketSegment; + } + + public void setMarketSegment(String marketSegment) { + this.marketSegment = marketSegment; + } + + public String getSourceCode() { + return sourceCode; + } + + public void setSourceCode(String sourceCode) { + this.sourceCode = sourceCode; + } + + public String getOriginCode() { + return originCode; + } + + public void setOriginCode(String originCode) { + this.originCode = originCode; + } + + public boolean isOnBehalfFlag() { + return onBehalfFlag; + } + + public void setOnBehalfFlag(boolean onBehalfFlag) { + this.onBehalfFlag = onBehalfFlag; + } + + public boolean isRedemReservationFlag() { + return redemReservationFlag; + } + + public void setRedemReservationFlag(boolean redemReservationFlag) { + this.redemReservationFlag = redemReservationFlag; + } + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + + public boolean isOptIn() { + return optIn; + } + + public void setOptIn(boolean optIn) { + this.optIn = optIn; + } + + public boolean isOptInComplete() { + return optInComplete; + } + + public void setOptInComplete(boolean optInComplete) { + this.optInComplete = optInComplete; + } + + public boolean isFinancialTransactionExists() { + return financialTransactionExists; + } + + public void setFinancialTransactionExists(boolean financialTransactionExists) { + this.financialTransactionExists = financialTransactionExists; + } + + public boolean isPrintRate() { + return printRate; + } + + public void setPrintRate(boolean printRate) { + this.printRate = printRate; + } + + public String getReferralYN() { + return referralYN; + } + + public void setReferralYN(String referralYN) { + this.referralYN = referralYN; + } + + public boolean isNoPost() { + return noPost; + } + + public void setNoPost(boolean noPost) { + this.noPost = noPost; + } + + public boolean isCommentsExists() { + return commentsExists; + } + + public void setCommentsExists(boolean commentsExists) { + this.commentsExists = commentsExists; + } + + public int getCommentsCount() { + return commentsCount; + } + + public void setCommentsCount(int commentsCount) { + this.commentsCount = commentsCount; + } + + public boolean isTracesExists() { + return tracesExists; + } + + public void setTracesExists(boolean tracesExists) { + this.tracesExists = tracesExists; + } + + public boolean isSpecialsExists() { + return specialsExists; + } + + public void setSpecialsExists(boolean specialsExists) { + this.specialsExists = specialsExists; + } + + public boolean isRoomPreferenceExists() { + return roomPreferenceExists; + } + + public void setRoomPreferenceExists(boolean roomPreferenceExists) { + this.roomPreferenceExists = roomPreferenceExists; + } + + public boolean isShareExists() { + return shareExists; + } + + public void setShareExists(boolean shareExists) { + this.shareExists = shareExists; + } + + public boolean isQueueExists() { + return queueExists; + } + + public void setQueueExists(boolean queueExists) { + this.queueExists = queueExists; + } + + public boolean isAlertExists() { + return alertExists; + } + + public void setAlertExists(boolean alertExists) { + this.alertExists = alertExists; + } + + public boolean isMessageExists() { + return messageExists; + } + + public void setMessageExists(boolean messageExists) { + this.messageExists = messageExists; + } + + public String getCheckOutTime() { + return checkOutTime; + } + + public void setCheckOutTime(String checkOutTime) { + this.checkOutTime = checkOutTime; + } + + public String getCheckInTime() { + return checkInTime; + } + + public void setCheckInTime(String checkInTime) { + this.checkInTime = checkInTime; + } + + public boolean isReturningGuest() { + return returningGuest; + } + + public void setReturningGuest(boolean returningGuest) { + this.returningGuest = returningGuest; + } + + public String getComputedReservationStatus() { + return computedReservationStatus; + } + + public void setComputedReservationStatus(String computedReservationStatus) { + this.computedReservationStatus = computedReservationStatus; + } + + public FetchBookingUniqueIDList getUniqueIDList() { + return uniqueIDList; + } + + public void setUniqueIDList(FetchBookingUniqueIDList uniqueIDList) { + this.uniqueIDList = uniqueIDList; + } + + public FetchBookingRoomStays getRoomStays() { + return roomStays; + } + + public void setRoomStays(FetchBookingRoomStays roomStays) { + this.roomStays = roomStays; + } + + public FetchBookingResGuests getResGuests() { + return resGuests; + } + + public void setResGuests(FetchBookingResGuests resGuests) { + this.resGuests = resGuests; + } + + public FetchBookingReservationHistory getReservationHistory() { + return reservationHistory; + } + + public void setReservationHistory(FetchBookingReservationHistory reservationHistory) { + this.reservationHistory = reservationHistory; + } + + public FetchBookingUserDefinedValues getUserDefinedValues() { + return userDefinedValues; + } + + public void setUserDefinedValues(FetchBookingUserDefinedValues userDefinedValues) { + this.userDefinedValues = userDefinedValues; + } + + public FetchBookingReservationPayments getReservationPayments() { + return reservationPayments; + } + + public void setReservationPayments(FetchBookingReservationPayments reservationPayments) { + this.reservationPayments = reservationPayments; + } + + public FetchBookingShareReservations getShareReservations() { + return shareReservations; + } + + public void setShareReservations(FetchBookingShareReservations shareReservations) { + this.shareReservations = shareReservations; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingMemberships.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingMemberships.java new file mode 100644 index 0000000..436b60a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingMemberships.java @@ -0,0 +1,20 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("Memberships") +public class FetchBookingMemberships { + + @XStreamAlias("NameMembership") + private FetchBookingNameMembership nameMembership; + + public FetchBookingNameMembership getNameMembership() { + return nameMembership; + } + + public void setNameMembership(FetchBookingNameMembership nameMembership) { + this.nameMembership = nameMembership; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingNameAddress.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingNameAddress.java new file mode 100644 index 0000000..2d06778 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingNameAddress.java @@ -0,0 +1,33 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("NameAddress") +public class FetchBookingNameAddress { + + @XStreamAlias("stateProv") + private String nameTitle; + + @XStreamAlias("countryCode") + private String firstName; + + public String getNameTitle() { + return nameTitle; + } + + public void setNameTitle(String nameTitle) { + this.nameTitle = nameTitle; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingNameMembership.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingNameMembership.java new file mode 100644 index 0000000..1e4ea62 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingNameMembership.java @@ -0,0 +1,104 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("NameMembership") +public class FetchBookingNameMembership { + + @XStreamAsAttribute + @XStreamAlias("displaySequence") + private String displaySequence; + + @XStreamAsAttribute + @XStreamAlias("usedInReservation") + private boolean usedInReservation; + + @XStreamAlias("membershipType") + private String membershipType; + + @XStreamAlias("membershipNumber") + private String membershipNumber; + + @XStreamAlias("memberName") + private String memberName; + + @XStreamAlias("effectiveDate") + private String effectiveDate; + + @XStreamAlias("currentPoints") + private String currentPoints; + + @XStreamAlias("membershipid") + private String membershipid; + + public String getDisplaySequence() { + return displaySequence; + } + + public void setDisplaySequence(String displaySequence) { + this.displaySequence = displaySequence; + } + + public boolean isUsedInReservation() { + return usedInReservation; + } + + public void setUsedInReservation(boolean usedInReservation) { + this.usedInReservation = usedInReservation; + } + + public String getMembershipType() { + return membershipType; + } + + public void setMembershipType(String membershipType) { + this.membershipType = membershipType; + } + + public String getMembershipNumber() { + return membershipNumber; + } + + public void setMembershipNumber(String membershipNumber) { + this.membershipNumber = membershipNumber; + } + + public String getMemberName() { + return memberName; + } + + public void setMemberName(String memberName) { + this.memberName = memberName; + } + + public String getEffectiveDate() { + return effectiveDate; + } + + public void setEffectiveDate(String effectiveDate) { + this.effectiveDate = effectiveDate; + } + + public String getCurrentPoints() { + return currentPoints; + } + + public void setCurrentPoints(String currentPoints) { + this.currentPoints = currentPoints; + } + + public String getMembershipid() { + return membershipid; + } + + public void setMembershipid(String membershipid) { + this.membershipid = membershipid; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingNamePhone.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingNamePhone.java new file mode 100644 index 0000000..6bcec18 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingNamePhone.java @@ -0,0 +1,22 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("NamePhone") +public class FetchBookingNamePhone { + + @XStreamAlias("PhoneNumber") + private String phoneNumber; + + public String getPhoneNumber() { + return phoneNumber; + } + + public void setPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingOtherPayment.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingOtherPayment.java new file mode 100644 index 0000000..d013f60 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingOtherPayment.java @@ -0,0 +1,25 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("OtherPayment") +public class FetchBookingOtherPayment { + + @XStreamAsAttribute + @XStreamAlias("type") + private String type; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPackage.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPackage.java new file mode 100644 index 0000000..753e0cc --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPackage.java @@ -0,0 +1,101 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + +@XStreamAlias("Package") +public class FetchBookingPackage { + + @XStreamAsAttribute + @XStreamAlias("packageCode") + private String packageCode; + + @XStreamAsAttribute + @XStreamAlias("source") + private String source; + + @XStreamAsAttribute + @XStreamAlias("taxIncluded") + private boolean taxIncluded; + + @XStreamAlias("PackageAmount") + private FetchBookingPackageAmount packageAmount; + + @XStreamAlias("TaxAmount") + private FetchBookingTaxAmount taxAmount; + + @XStreamAlias("Allowance") + private FetchBookingAllowance allowance; + + @XStreamAlias("Description") + private FetchBookingDescription description; + + @XStreamAlias("ShortDescription") + private FetchBookingShortDescription shortDescription; + + public String getPackageCode() { + return packageCode; + } + + public void setPackageCode(String packageCode) { + this.packageCode = packageCode; + } + + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } + + public boolean isTaxIncluded() { + return taxIncluded; + } + + public void setTaxIncluded(boolean taxIncluded) { + this.taxIncluded = taxIncluded; + } + + public FetchBookingPackageAmount getPackageAmount() { + return packageAmount; + } + + public void setPackageAmount(FetchBookingPackageAmount packageAmount) { + this.packageAmount = packageAmount; + } + + public FetchBookingTaxAmount getTaxAmount() { + return taxAmount; + } + + public void setTaxAmount(FetchBookingTaxAmount taxAmount) { + this.taxAmount = taxAmount; + } + + public FetchBookingAllowance getAllowance() { + return allowance; + } + + public void setAllowance(FetchBookingAllowance allowance) { + this.allowance = allowance; + } + + public FetchBookingDescription getDescription() { + return description; + } + + public void setDescription(FetchBookingDescription description) { + this.description = description; + } + + public FetchBookingShortDescription getShortDescription() { + return shortDescription; + } + + public void setShortDescription(FetchBookingShortDescription shortDescription) { + this.shortDescription = shortDescription; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPackageAmount.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPackageAmount.java new file mode 100644 index 0000000..c1e90ea --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPackageAmount.java @@ -0,0 +1,45 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; + +@XStreamAlias("PackageAmount") +@XStreamConverter(FetchBookingPackageAmountConvert.class) +public class FetchBookingPackageAmount { + + @XStreamAsAttribute + @XStreamAlias("currencyCode") + private String currencyCode; + + @XStreamAsAttribute + @XStreamAlias("decimals") + private String decimals; + + private String totalValue; + + public String getCurrencyCode() { + return currencyCode; + } + + public void setCurrencyCode(String currencyCode) { + this.currencyCode = currencyCode; + } + + public String getDecimals() { + return decimals; + } + + public void setDecimals(String decimals) { + this.decimals = decimals; + } + + public String getTotalValue() { + return totalValue; + } + + public void setTotalValue(String totalValue) { + this.totalValue = totalValue; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPackageAmountConvert.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPackageAmountConvert.java new file mode 100644 index 0000000..ad7b0f1 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPackageAmountConvert.java @@ -0,0 +1,39 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +public class FetchBookingPackageAmountConvert implements Converter { + //转换条件 + @Override + public boolean canConvert(Class type) { + return type.equals(FetchBookingPackageAmount.class); + } + /** + * 将java对象转为xml时使用 + */ + @Override + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + FetchBookingPackageAmount base = (FetchBookingPackageAmount) source; + writer.addAttribute("currencyCode", base.getCurrencyCode()); + writer.addAttribute("decimals", base.getDecimals()); + writer.setValue(base.getTotalValue()); + } + /** + * 将xml转为java对象使用 + */ + @Override + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + // 在解析order元素时,先创建一个Order对象 + FetchBookingPackageAmount base = new FetchBookingPackageAmount(); + // 将order元素的name属性设置为Order对象的name属性值 + base.setCurrencyCode(reader.getAttribute("currencyCode")); + base.setDecimals(reader.getAttribute("decimals")); + // 将order元素的txt值设置为Order对象的value值 + base.setTotalValue(reader.getValue()); + return base; + } +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPackages.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPackages.java new file mode 100644 index 0000000..1b7835d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPackages.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("Packages") +public class FetchBookingPackages { + + @XStreamAlias("Package") + private FetchBookingPackage packagea; + + public FetchBookingPackage getPackagea() { + return packagea; + } + + public void setPackagea(FetchBookingPackage packagea) { + this.packagea = packagea; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPayment.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPayment.java new file mode 100644 index 0000000..6ab7dd1 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPayment.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("Payment") +public class FetchBookingPayment { + + @XStreamAlias("PaymentsAccepted") + private FetchBookingPaymentsAccepted paymentsAccepted; + + public FetchBookingPaymentsAccepted getPaymentsAccepted() { + return paymentsAccepted; + } + + public void setPaymentsAccepted(FetchBookingPaymentsAccepted paymentsAccepted) { + this.paymentsAccepted = paymentsAccepted; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPaymentType.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPaymentType.java new file mode 100644 index 0000000..dde4530 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPaymentType.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("PaymentType") +public class FetchBookingPaymentType { + + @XStreamAlias("OtherPayment") + private FetchBookingOtherPayment otherPayment; + + public FetchBookingOtherPayment getOtherPayment() { + return otherPayment; + } + + public void setOtherPayment(FetchBookingOtherPayment otherPayment) { + this.otherPayment = otherPayment; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPaymentsAccepted.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPaymentsAccepted.java new file mode 100644 index 0000000..6306c1a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPaymentsAccepted.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("PaymentsAccepted") +public class FetchBookingPaymentsAccepted { + + @XStreamAlias("PaymentType") + private FetchBookingPaymentType paymentType; + + public FetchBookingPaymentType getPaymentType() { + return paymentType; + } + + public void setPaymentType(FetchBookingPaymentType paymentType) { + this.paymentType = paymentType; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPersonName.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPersonName.java new file mode 100644 index 0000000..ad046cf --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPersonName.java @@ -0,0 +1,45 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("PersonName") +public class FetchBookingPersonName { + + @XStreamAlias("nameTitle") + private String nameTitle; + + @XStreamAlias("firstName") + private String firstName; + + @XStreamAlias("lastName") + private String lastName; + + public String getNameTitle() { + return nameTitle; + } + + public void setNameTitle(String nameTitle) { + this.nameTitle = nameTitle; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPhones.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPhones.java new file mode 100644 index 0000000..b156830 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingPhones.java @@ -0,0 +1,23 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("Phones") +public class FetchBookingPhones { + + @XStreamImplicit(itemFieldName="NamePhone") + private List namePhone; + + public List getNamePhone() { + return namePhone; + } + + public void setNamePhone(List namePhone) { + this.namePhone = namePhone; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingProfile.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingProfile.java new file mode 100644 index 0000000..18a843d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingProfile.java @@ -0,0 +1,75 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("Profile") +public class FetchBookingProfile { + + @XStreamAlias("ProfileIDs") + private FetchBookingProfileIDs profileIDs; + + @XStreamAlias("Customer") + private FetchBookingCustomer customer; + + @XStreamAlias("Addresses") + private FetchBookingAddresses Addresses; + + @XStreamAlias("Phones") + private FetchBookingPhones Phones; + + @XStreamAlias("Memberships") + private FetchBookingMemberships memberships; + + @XStreamAlias("Company") + private FetchBookingCompany company; + + public FetchBookingProfileIDs getProfileIDs() { + return profileIDs; + } + + public void setProfileIDs(FetchBookingProfileIDs profileIDs) { + this.profileIDs = profileIDs; + } + + public FetchBookingCustomer getCustomer() { + return customer; + } + + public void setCustomer(FetchBookingCustomer customer) { + this.customer = customer; + } + + public FetchBookingAddresses getAddresses() { + return Addresses; + } + + public void setAddresses(FetchBookingAddresses addresses) { + Addresses = addresses; + } + + public FetchBookingPhones getPhones() { + return Phones; + } + + public void setPhones(FetchBookingPhones phones) { + Phones = phones; + } + + public FetchBookingMemberships getMemberships() { + return memberships; + } + + public void setMemberships(FetchBookingMemberships memberships) { + this.memberships = memberships; + } + + public FetchBookingCompany getCompany() { + return company; + } + + public void setCompany(FetchBookingCompany company) { + this.company = company; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingProfileIDs.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingProfileIDs.java new file mode 100644 index 0000000..f159863 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingProfileIDs.java @@ -0,0 +1,22 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("ProfileIDs") +public class FetchBookingProfileIDs { + + @XStreamAlias("UniqueID") + private String uniqueID; + + public String getUniqueID() { + return uniqueID; + } + + public void setUniqueID(String uniqueID) { + this.uniqueID = uniqueID; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingProfiles.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingProfiles.java new file mode 100644 index 0000000..642d850 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingProfiles.java @@ -0,0 +1,23 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("Profiles") +public class FetchBookingProfiles { + + @XStreamImplicit(itemFieldName="Profile") + private List profile; + + public List getProfile() { + return profile; + } + + public void setProfile(List profile) { + this.profile = profile; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRate.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRate.java new file mode 100644 index 0000000..ca459dc --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRate.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("Rate") +public class FetchBookingRate { + + @XStreamAlias("Base") + private FetchBookingBase base; + + public FetchBookingBase getBase() { + return base; + } + + public void setBase(FetchBookingBase base) { + this.base = base; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRatePlan.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRatePlan.java new file mode 100644 index 0000000..f8d84aa --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRatePlan.java @@ -0,0 +1,89 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + +@XStreamAlias("RatePlan") +public class FetchBookingRatePlan { + + @XStreamAsAttribute + @XStreamAlias("ratePlanCode") + private String ratePlanCode; + + @XStreamAsAttribute + @XStreamAlias("suppressRate") + private String suppressRate; + + @XStreamAsAttribute + @XStreamAlias("promotionCode") + private String promotionCode; + + @XStreamAlias("RatePlanDescription") + private FetchBookingRatePlanDescription ratePlanDescription; + + @XStreamAlias("AdditionalDetails") + private FetchBookingAdditionalDetails additionalDetails; + + @XStreamAlias("CancellationDateTime") + private String cancellationDateTime; + + @XStreamAlias("DepositRequired") + private FetchBookingDepositRequired depositRequired; + + public String getRatePlanCode() { + return ratePlanCode; + } + + public void setRatePlanCode(String ratePlanCode) { + this.ratePlanCode = ratePlanCode; + } + + public String getSuppressRate() { + return suppressRate; + } + + public void setSuppressRate(String suppressRate) { + this.suppressRate = suppressRate; + } + + public String getPromotionCode() { + return promotionCode; + } + + public void setPromotionCode(String promotionCode) { + this.promotionCode = promotionCode; + } + + public FetchBookingRatePlanDescription getRatePlanDescription() { + return ratePlanDescription; + } + + public void setRatePlanDescription(FetchBookingRatePlanDescription ratePlanDescription) { + this.ratePlanDescription = ratePlanDescription; + } + + public FetchBookingAdditionalDetails getAdditionalDetails() { + return additionalDetails; + } + + public void setAdditionalDetails(FetchBookingAdditionalDetails additionalDetails) { + this.additionalDetails = additionalDetails; + } + + public String getCancellationDateTime() { + return cancellationDateTime; + } + + public void setCancellationDateTime(String cancellationDateTime) { + this.cancellationDateTime = cancellationDateTime; + } + + public FetchBookingDepositRequired getDepositRequired() { + return depositRequired; + } + + public void setDepositRequired(FetchBookingDepositRequired depositRequired) { + this.depositRequired = depositRequired; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRatePlanDescription.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRatePlanDescription.java new file mode 100644 index 0000000..bb19aae --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRatePlanDescription.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("RatePlanDescription") +public class FetchBookingRatePlanDescription { + + @XStreamAlias("Text") + private String text; + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRatePlans.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRatePlans.java new file mode 100644 index 0000000..0c956d4 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRatePlans.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("RatePlans") +public class FetchBookingRatePlans { + + @XStreamAlias("RatePlan") + private FetchBookingRatePlan ratePlan; + + public FetchBookingRatePlan getRatePlan() { + return ratePlan; + } + + public void setRatePlan(FetchBookingRatePlan ratePlan) { + this.ratePlan = ratePlan; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRates.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRates.java new file mode 100644 index 0000000..c369130 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRates.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("Rates") +public class FetchBookingRates { + + @XStreamAlias("Rate") + private FutureBookingSummaryRate rate; + + public FutureBookingSummaryRate getRate() { + return rate; + } + + public void setRate(FutureBookingSummaryRate rate) { + this.rate = rate; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRequest.java new file mode 100644 index 0000000..fc2a6e0 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRequest.java @@ -0,0 +1,66 @@ +package com.mgm.mcrm.booking.dtos.opera; + + +public class FetchBookingRequest { + + private String transactionID; + private String timeStamp; + private StringBuffer requestString; + private String confirmationNo; + + public FetchBookingRequest() { + } + + public StringBuffer getRequestString() { + this.requestString = new StringBuffer(); + this.requestString.append(""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "+this.confirmationNo+""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(""); + + return this.requestString; + } + + public String getResponseString() { + String resString = "http://webservices.micros.com/ows/5.1/Reservation.wsdl#FetchBookingResponseurn:uuid:a111da8b-5f0a-4e21-b058-060f2b4551dfurn:uuid:19c82f63-f225-4ccd-a385-ddb6f632af8ahttp://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous1223875512224736Casino Overdraft CompCancel By 17-SEP-25Tax included 10 PCT Service Charge 5 PCT Government Tax Thank you for bookingA deposit is not required for guarantee of your reservation0001-01-01T00:00:0000Grand Deluxe Ocean View Twin RoomGrand Deluxe Ocean View Twin Room22002025-09-17T00:00:002025-09-19T00:00:00MGM MACAU44000BASE RATE1913.0400120083 10% Service Charge191.3R0012001800120098 5% Government Tax95.65R00120018BASE RATE1913.0400120083 10% Service Charge191.3R0012001800120098 5% Government Tax95.65R0012001890059MrTai Man10110015Chan張敬å·?HONG KONGHK085387654321winnieao@mgm.mowinnieao@mgm.moGP10110015Chan Tai Man1011001504429812743704Casino Mass Macau 2025SOURCE100712"; + + return resString; + } + + public String getTransactionID() { + return transactionID; + } + + public void setTransactionID(String transactionID) { + this.transactionID = transactionID; + } + + public String getTimeStamp() { + return timeStamp; + } + + public void setTimeStamp(String timeStamp) { + this.timeStamp = timeStamp; + } + + + public String getConfirmationNo() { + return confirmationNo; + } + + public void setConfirmationNo(String confirmationNo) { + this.confirmationNo = confirmationNo; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResGuest.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResGuest.java new file mode 100644 index 0000000..feca9e9 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResGuest.java @@ -0,0 +1,67 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + +@XStreamAlias("ResGuest") +public class FetchBookingResGuest { + + @XStreamAsAttribute + @XStreamAlias("resGuestRPH") + private String resGuestRPH; + + @XStreamAsAttribute + @XStreamAlias("arrivalTime") + private String arrivalTime; + + @XStreamAlias("ArrivalTransport") + private FetchBookingArrivalTransport arrivalTransport; + + @XStreamAlias("DepartureTransport") + private FetchBookingDepartureTransport departureTransport; + + @XStreamAlias("Profiles") + private FetchBookingProfiles profiles; + + public FetchBookingProfiles getProfiles() { + return profiles; + } + + public void setProfiles(FetchBookingProfiles profiles) { + this.profiles = profiles; + } + + public String getResGuestRPH() { + return resGuestRPH; + } + + public void setResGuestRPH(String resGuestRPH) { + this.resGuestRPH = resGuestRPH; + } + + public String getArrivalTime() { + return arrivalTime; + } + + public void setArrivalTime(String arrivalTime) { + this.arrivalTime = arrivalTime; + } + + public FetchBookingArrivalTransport getArrivalTransport() { + return arrivalTransport; + } + + public void setArrivalTransport(FetchBookingArrivalTransport arrivalTransport) { + this.arrivalTransport = arrivalTransport; + } + + public FetchBookingDepartureTransport getDepartureTransport() { + return departureTransport; + } + + public void setDepartureTransport(FetchBookingDepartureTransport departureTransport) { + this.departureTransport = departureTransport; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResGuestRPH.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResGuestRPH.java new file mode 100644 index 0000000..4feaec0 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResGuestRPH.java @@ -0,0 +1,26 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("ResGuestRPH") +public class FetchBookingResGuestRPH { + + @XStreamAsAttribute + @XStreamAlias("RPH") + private String RPH; + + public String getrPH() { + return RPH; + } + + public void setRPH(String rPH) { + this.RPH = rPH; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResGuestRPHs.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResGuestRPHs.java new file mode 100644 index 0000000..6471155 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResGuestRPHs.java @@ -0,0 +1,20 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("ResGuestRPHs") +public class FetchBookingResGuestRPHs { + + @XStreamAlias("ResGuestRPH") + private FetchBookingResGuestRPH resGuestRPH; + + public FetchBookingResGuestRPH getResGuestRPH() { + return resGuestRPH; + } + + public void setResGuestRPH(FetchBookingResGuestRPH resGuestRPH) { + this.resGuestRPH = resGuestRPH; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResGuests.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResGuests.java new file mode 100644 index 0000000..cba64b9 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResGuests.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("ResGuests") +public class FetchBookingResGuests { + + @XStreamAlias("ResGuest") + private FetchBookingResGuest resGuest; + + public FetchBookingResGuest getResGuest() { + return resGuest; + } + + public void setResGuest(FetchBookingResGuest resGuest) { + this.resGuest = resGuest; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingReservationGuarantee.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingReservationGuarantee.java new file mode 100644 index 0000000..ad043e6 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingReservationGuarantee.java @@ -0,0 +1,38 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("ReservationGuarantee") +public class FetchBookingReservationGuarantee { + + @XStreamAsAttribute + @XStreamAlias("guaranteeType") + private String guaranteeType; + + @XStreamAsAttribute + @XStreamAlias("paymentType") + private String paymentType; + + public String getGuaranteeType() { + return guaranteeType; + } + + public void setGuaranteeType(String guaranteeType) { + this.guaranteeType = guaranteeType; + } + + public String getPaymentType() { + return paymentType; + } + + public void setPaymentType(String paymentType) { + this.paymentType = paymentType; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingReservationHistory.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingReservationHistory.java new file mode 100644 index 0000000..83fac73 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingReservationHistory.java @@ -0,0 +1,62 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("ReservationHistory") +public class FetchBookingReservationHistory { + + @XStreamAsAttribute + @XStreamAlias("insertUser") + private String insertUser; + + @XStreamAsAttribute + @XStreamAlias("insertDate") + private String insertDate; + + @XStreamAsAttribute + @XStreamAlias("updateUser") + private String updateUser; + + @XStreamAsAttribute + @XStreamAlias("updateDate") + private String updateDate; + + public String getInsertUser() { + return insertUser; + } + + public void setInsertUser(String insertUser) { + this.insertUser = insertUser; + } + + public String getInsertDate() { + return insertDate; + } + + public void setInsertDate(String insertDate) { + this.insertDate = insertDate; + } + + public String getUpdateUser() { + return updateUser; + } + + public void setUpdateUser(String updateUser) { + this.updateUser = updateUser; + } + + public String getUpdateDate() { + return updateDate; + } + + public void setUpdateDate(String updateDate) { + this.updateDate = updateDate; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingReservationPaymentInfo.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingReservationPaymentInfo.java new file mode 100644 index 0000000..dd2dc0e --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingReservationPaymentInfo.java @@ -0,0 +1,37 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("ReservationPaymentInfo") +public class FetchBookingReservationPaymentInfo { + + @XStreamAsAttribute + @XStreamAlias("Window") + private String window; + + @XStreamAlias("PaymentType") + private String paymentType; + + public String getWindow() { + return window; + } + + public void setWindow(String window) { + this.window = window; + } + + public String getPaymentType() { + return paymentType; + } + + public void setPaymentType(String paymentType) { + this.paymentType = paymentType; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingReservationPayments.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingReservationPayments.java new file mode 100644 index 0000000..7ea15e1 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingReservationPayments.java @@ -0,0 +1,23 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("ReservationPayments") +public class FetchBookingReservationPayments { + + @XStreamAlias("ReservationPaymentInfo") + private FetchBookingReservationPaymentInfo reservationPaymentInfo; + + public FetchBookingReservationPaymentInfo getReservationPaymentInfo() { + return reservationPaymentInfo; + } + + public void setReservationPaymentInfo(FetchBookingReservationPaymentInfo reservationPaymentInfo) { + this.reservationPaymentInfo = reservationPaymentInfo; + } + + + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResponse.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResponse.java new file mode 100644 index 0000000..f6a33eb --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResponse.java @@ -0,0 +1,45 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.io.Serializable; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("FetchBookingResponse") +public class FetchBookingResponse implements Serializable { + + + @XStreamAlias("Result") + private GuestRequestsResult result; + + @XStreamAlias("HotelReservation") + private FetchBookingHotelReservation hotelReservation; + + + public FetchBookingResponse() { + + } + + + public GuestRequestsResult getResult() { + return result; + } + + + public void setResult(GuestRequestsResult result) { + this.result = result; + } + + + public FetchBookingHotelReservation getHotelReservation() { + return hotelReservation; + } + + + public void setHotelReservation(FetchBookingHotelReservation hotelReservation) { + this.hotelReservation = hotelReservation; + } + + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResult.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResult.java new file mode 100644 index 0000000..a04b75b --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingResult.java @@ -0,0 +1,44 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + +@XStreamAlias("Result") +public class FetchBookingResult { + + @XStreamAlias("resultStatusFlag") + @XStreamAsAttribute() + private String resultStatusFlag; + + @XStreamAlias("GDSError") + private String gDSError; + + @XStreamAlias("OperaErrorCode") + private String operaErrorCode; + + + public String getResultStatusFlag() { + return resultStatusFlag; + } + + public void setResultStatusFlag(String resultStatusFlag) { + this.resultStatusFlag = resultStatusFlag; + } + + public String getgDSError() { + return gDSError; + } + + public void setgDSError(String gDSError) { + this.gDSError = gDSError; + } + + public String getOperaErrorCode() { + return operaErrorCode; + } + + public void setOperaErrorCode(String operaErrorCode) { + this.operaErrorCode = operaErrorCode; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomRate.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomRate.java new file mode 100644 index 0000000..6436583 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomRate.java @@ -0,0 +1,56 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + +@XStreamAlias("RoomRate") +public class FetchBookingRoomRate { + + @XStreamAlias("Rates") + private FetchBookingRates rates; + + @XStreamAsAttribute + @XStreamAlias("roomTypeCode") + private String roomTypeCode; + + @XStreamAsAttribute + @XStreamAlias("ratePlanCode") + private String ratePlanCode; + + @XStreamAsAttribute + @XStreamAlias("suppressRate") + private boolean suppressRate; + + public FetchBookingRates getRates() { + return rates; + } + + public void setRates(FetchBookingRates rates) { + this.rates = rates; + } + + public String getRoomTypeCode() { + return roomTypeCode; + } + + public void setRoomTypeCode(String roomTypeCode) { + this.roomTypeCode = roomTypeCode; + } + + public String getRatePlanCode() { + return ratePlanCode; + } + + public void setRatePlanCode(String ratePlanCode) { + this.ratePlanCode = ratePlanCode; + } + + public boolean isSuppressRate() { + return suppressRate; + } + + public void setSuppressRate(boolean suppressRate) { + this.suppressRate = suppressRate; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomRateAndPackages.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomRateAndPackages.java new file mode 100644 index 0000000..1a35166 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomRateAndPackages.java @@ -0,0 +1,49 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("RoomRateAndPackages") +public class FetchBookingRoomRateAndPackages { + + @XStreamAsAttribute + @XStreamAlias("TotalCharges") + private String totalCharges; + + @XStreamAsAttribute + @XStreamAlias("decimals") + private String decimals; + + @XStreamImplicit(itemFieldName="Charges") + private List listCharges; + + public String getTotalCharges() { + return totalCharges; + } + + public void setTotalCharges(String totalCharges) { + this.totalCharges = totalCharges; + } + + public String getDecimals() { + return decimals; + } + + public void setDecimals(String decimals) { + this.decimals = decimals; + } + + public List getListCharges() { + return listCharges; + } + + public void setListCharges(List listCharges) { + this.listCharges = listCharges; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomRates.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomRates.java new file mode 100644 index 0000000..ff52a80 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomRates.java @@ -0,0 +1,24 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("RoomRates") +public class FetchBookingRoomRates { + + @XStreamImplicit(itemFieldName="RoomRate") + private List roomRate; + + public List getRoomRate() { + return roomRate; + } + + public void setRoomRate(List roomRate) { + this.roomRate = roomRate; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomStay.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomStay.java new file mode 100644 index 0000000..5de8e51 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomStay.java @@ -0,0 +1,174 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + +@XStreamAlias("RoomStay") +public class FetchBookingRoomStay { + + @XStreamAlias("RatePlans") + private FetchBookingRatePlans ratePlans; + + @XStreamAlias("RoomTypes") + private FetchBookingRoomTypes roomTypes; + + @XStreamAlias("RoomRates") + private FetchBookingRoomRates roomRates; + + @XStreamAlias("GuestCounts") + private FetchBookingGuestCounts guestCounts; + + @XStreamAlias("Guarantee") + private FetchBookingGuarantee guarantee; + + @XStreamAlias("TimeSpan") + private FetchBookingTimeSpan timeSpan; + + @XStreamAlias("Payment") + private FetchBookingPayment payment; + + @XStreamAlias("CancelTerm") + private FetchBookingCancelTerm cancelTerm; + + @XStreamAlias("HotelReference") + private FetchBookingHotelReference hotelReference; + + @XStreamAsAttribute + @XStreamAlias("Total") + private FetchBookingTotal total; + + @XStreamAlias("CurrentBalance") + private FetchBookingCurrentBalance currentBalance; + + @XStreamAlias("ResGuestRPHs") + private FetchBookingResGuestRPHs resGuestRPHs; + + @XStreamAlias("Packages") + private FetchBookingPackage Packages; + + @XStreamAlias("Comments") + private FetchBookingComments Comments; + + @XStreamAlias("ExpectedCharges") + private FetchBookingExpectedCharges expectedCharges; + + public FetchBookingRatePlans getRatePlans() { + return ratePlans; + } + + public void setRatePlans(FetchBookingRatePlans ratePlans) { + this.ratePlans = ratePlans; + } + + public FetchBookingRoomTypes getRoomTypes() { + return roomTypes; + } + + public void setRoomTypes(FetchBookingRoomTypes roomTypes) { + this.roomTypes = roomTypes; + } + + public FetchBookingRoomRates getRoomRates() { + return roomRates; + } + + public void setRoomRates(FetchBookingRoomRates roomRates) { + this.roomRates = roomRates; + } + + public FetchBookingGuestCounts getGuestCounts() { + return guestCounts; + } + + public void setGuestCounts(FetchBookingGuestCounts guestCounts) { + this.guestCounts = guestCounts; + } + + public FetchBookingGuarantee getGuarantee() { + return guarantee; + } + + public void setGuarantee(FetchBookingGuarantee guarantee) { + this.guarantee = guarantee; + } + + public FetchBookingTimeSpan getTimeSpan() { + return timeSpan; + } + + public void setTimeSpan(FetchBookingTimeSpan timeSpan) { + this.timeSpan = timeSpan; + } + + public FetchBookingPayment getPayment() { + return payment; + } + + public void setPayment(FetchBookingPayment payment) { + this.payment = payment; + } + + public FetchBookingCancelTerm getCancelTerm() { + return cancelTerm; + } + + public void setCancelTerm(FetchBookingCancelTerm cancelTerm) { + this.cancelTerm = cancelTerm; + } + + public FetchBookingHotelReference getHotelReference() { + return hotelReference; + } + + public void setHotelReference(FetchBookingHotelReference hotelReference) { + this.hotelReference = hotelReference; + } + + public FetchBookingTotal getTotal() { + return total; + } + + public void setTotal(FetchBookingTotal total) { + this.total = total; + } + + public FetchBookingCurrentBalance getCurrentBalance() { + return currentBalance; + } + + public void setCurrentBalance(FetchBookingCurrentBalance currentBalance) { + this.currentBalance = currentBalance; + } + + public FetchBookingResGuestRPHs getResGuestRPHs() { + return resGuestRPHs; + } + + public void setResGuestRPHs(FetchBookingResGuestRPHs resGuestRPHs) { + this.resGuestRPHs = resGuestRPHs; + } + + public FetchBookingPackage getPackages() { + return Packages; + } + + public void setPackages(FetchBookingPackage packages) { + Packages = packages; + } + + public FetchBookingComments getComments() { + return Comments; + } + + public void setComments(FetchBookingComments comments) { + Comments = comments; + } + + public FetchBookingExpectedCharges getExpectedCharges() { + return expectedCharges; + } + + public void setExpectedCharges(FetchBookingExpectedCharges expectedCharges) { + this.expectedCharges = expectedCharges; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomStays.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomStays.java new file mode 100644 index 0000000..40c5f4d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomStays.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("RoomStays") +public class FetchBookingRoomStays { + + @XStreamAlias("RoomStay") + private FetchBookingRoomStay roomStay; + + public FetchBookingRoomStay getRoomStay() { + return roomStay; + } + + public void setRoomStay(FetchBookingRoomStay roomStay) { + this.roomStay = roomStay; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomToChargeDescription.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomToChargeDescription.java new file mode 100644 index 0000000..0905896 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomToChargeDescription.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("RoomToChargeDescription") +public class FetchBookingRoomToChargeDescription { + + @XStreamAlias("Text") + private String text; + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomToChargeShortDescription.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomToChargeShortDescription.java new file mode 100644 index 0000000..f0efff8 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomToChargeShortDescription.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("RoomToChargeShortDescription") +public class FetchBookingRoomToChargeShortDescription { + + @XStreamAlias("Text") + private String text; + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomType.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomType.java new file mode 100644 index 0000000..e2c81a8 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomType.java @@ -0,0 +1,113 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + +@XStreamAlias("RoomType") +public class FetchBookingRoomType { + + @XStreamAlias("RoomTypeDescription") + private FetchBookingRoomTypeDescription roomTypeDescription; + + @XStreamAlias("RoomTypeShortDescription") + private FetchBookingRoomTypeShortDescription roomTypeShortDescription; + + @XStreamAlias("RoomToChargeDescription") + private FetchBookingRoomToChargeDescription roomToChargeDescription; + + @XStreamAlias("RoomToChargeShortDescription") + private FetchBookingRoomToChargeShortDescription roomToChargeShortDescription; + + @XStreamAsAttribute + @XStreamAlias("roomTypeCode") + private String roomTypeCode; + + @XStreamAsAttribute + @XStreamAlias("invBlockCode") + private String invBlockCode; + + @XStreamAsAttribute + @XStreamAlias("numberOfUnits") + private int numberOfUnits; + + @XStreamAsAttribute + @XStreamAlias("roomToChargeCode") + private String roomToChargeCode; + + @XStreamAsAttribute + @XStreamAlias("roomClass") + private String roomClass; + + public String getRoomTypeCode() { + return roomTypeCode; + } + + public void setRoomTypeCode(String roomTypeCode) { + this.roomTypeCode = roomTypeCode; + } + + public String getInvBlockCode() { + return invBlockCode; + } + + public void setInvBlockCode(String invBlockCode) { + this.invBlockCode = invBlockCode; + } + + public int getNumberOfUnits() { + return numberOfUnits; + } + + public void setNumberOfUnits(int numberOfUnits) { + this.numberOfUnits = numberOfUnits; + } + + public String getRoomToChargeCode() { + return roomToChargeCode; + } + + public void setRoomToChargeCode(String roomToChargeCode) { + this.roomToChargeCode = roomToChargeCode; + } + + public String getRoomClass() { + return roomClass; + } + + public void setRoomClass(String roomClass) { + this.roomClass = roomClass; + } + + public FetchBookingRoomTypeDescription getRoomTypeDescription() { + return roomTypeDescription; + } + + public void setRoomTypeDescription(FetchBookingRoomTypeDescription roomTypeDescription) { + this.roomTypeDescription = roomTypeDescription; + } + + public FetchBookingRoomTypeShortDescription getRoomTypeShortDescription() { + return roomTypeShortDescription; + } + + public void setRoomTypeShortDescription(FetchBookingRoomTypeShortDescription roomTypeShortDescription) { + this.roomTypeShortDescription = roomTypeShortDescription; + } + + public FetchBookingRoomToChargeDescription getRoomToChargeDescription() { + return roomToChargeDescription; + } + + public void setRoomToChargeDescription(FetchBookingRoomToChargeDescription roomToChargeDescription) { + this.roomToChargeDescription = roomToChargeDescription; + } + + public FetchBookingRoomToChargeShortDescription getRoomToChargeShortDescription() { + return roomToChargeShortDescription; + } + + public void setRoomToChargeShortDescription(FetchBookingRoomToChargeShortDescription roomToChargeShortDescription) { + this.roomToChargeShortDescription = roomToChargeShortDescription; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomTypeDescription.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomTypeDescription.java new file mode 100644 index 0000000..1dc5296 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomTypeDescription.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("RoomTypeDescription") +public class FetchBookingRoomTypeDescription { + + @XStreamAlias("Text") + private String text; + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomTypeShortDescription.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomTypeShortDescription.java new file mode 100644 index 0000000..13cab4d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomTypeShortDescription.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("RoomTypeShortDescription") +public class FetchBookingRoomTypeShortDescription { + + @XStreamAlias("Text") + private String text; + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomTypes.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomTypes.java new file mode 100644 index 0000000..4cd4a19 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingRoomTypes.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("RoomTypes") +public class FetchBookingRoomTypes { + + @XStreamAlias("RoomType") + private FetchBookingRoomType roomType; + + public FetchBookingRoomType getRoomType() { + return roomType; + } + + public void setRoomType(FetchBookingRoomType roomType) { + this.roomType = roomType; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingShareReservationDetails.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingShareReservationDetails.java new file mode 100644 index 0000000..3a133ae --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingShareReservationDetails.java @@ -0,0 +1,55 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("ShareReservationDetails") +public class FetchBookingShareReservationDetails { + + @XStreamAlias("UniqueIDList") + private FetchBookingUniqueIDList uniqueIDList; + + @XStreamAlias("Profiles") + private FetchBookingProfiles profiles; + + @XStreamAlias("GuestCounts") + private FetchBookingGuestCounts guestCounts; + + @XStreamAlias("ReservationGuarantee") + private FetchBookingReservationGuarantee reservationGuarantee; + + public FetchBookingUniqueIDList getUniqueIDList() { + return uniqueIDList; + } + + public void setUniqueIDList(FetchBookingUniqueIDList uniqueIDList) { + this.uniqueIDList = uniqueIDList; + } + + public FetchBookingProfiles getProfiles() { + return profiles; + } + + public void setProfiles(FetchBookingProfiles profiles) { + this.profiles = profiles; + } + + public FetchBookingGuestCounts getGuestCounts() { + return guestCounts; + } + + public void setGuestCounts(FetchBookingGuestCounts guestCounts) { + this.guestCounts = guestCounts; + } + + public FetchBookingReservationGuarantee getReservationGuarantee() { + return reservationGuarantee; + } + + public void setReservationGuarantee(FetchBookingReservationGuarantee reservationGuarantee) { + this.reservationGuarantee = reservationGuarantee; + } + + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingShareReservations.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingShareReservations.java new file mode 100644 index 0000000..3711110 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingShareReservations.java @@ -0,0 +1,24 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("ShareReservations") +public class FetchBookingShareReservations { + + @XStreamImplicit(itemFieldName="ShareReservationDetails") + private List shareReservationDetails; + + public List getShareReservationDetails() { + return shareReservationDetails; + } + + public void setShareReservationDetails(List shareReservationDetails) { + this.shareReservationDetails = shareReservationDetails; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingShortDescription.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingShortDescription.java new file mode 100644 index 0000000..cc08153 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingShortDescription.java @@ -0,0 +1,20 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("ShortDescription") +public class FetchBookingShortDescription { + + @XStreamAlias("Text") + private FetchBookingText text; + + public FetchBookingText getText() { + return text; + } + + public void setText(FetchBookingText text) { + this.text = text; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTaxAmount.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTaxAmount.java new file mode 100644 index 0000000..01f4522 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTaxAmount.java @@ -0,0 +1,45 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; + +@XStreamAlias("TaxAmount") +@XStreamConverter(FetchBookingTaxAmountConvert.class) +public class FetchBookingTaxAmount { + + @XStreamAsAttribute + @XStreamAlias("currencyCode") + private String currencyCode; + + @XStreamAsAttribute + @XStreamAlias("decimals") + private String decimals; + + private String totalValue; + + public String getCurrencyCode() { + return currencyCode; + } + + public void setCurrencyCode(String currencyCode) { + this.currencyCode = currencyCode; + } + + public String getDecimals() { + return decimals; + } + + public void setDecimals(String decimals) { + this.decimals = decimals; + } + + public String getTotalValue() { + return totalValue; + } + + public void setTotalValue(String totalValue) { + this.totalValue = totalValue; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTaxAmountConvert.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTaxAmountConvert.java new file mode 100644 index 0000000..d8d113f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTaxAmountConvert.java @@ -0,0 +1,39 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +public class FetchBookingTaxAmountConvert implements Converter { + //转换条件 + @Override + public boolean canConvert(Class type) { + return type.equals(FetchBookingTaxAmount.class); + } + /** + * 将java对象转为xml时使用 + */ + @Override + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + FetchBookingTaxAmount base = (FetchBookingTaxAmount) source; + writer.addAttribute("currencyCode", base.getCurrencyCode()); + writer.addAttribute("decimals", base.getDecimals()); + writer.setValue(base.getTotalValue()); + } + /** + * 将xml转为java对象使用 + */ + @Override + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + // 在解析order元素时,先创建一个Order对象 + FetchBookingTaxAmount base = new FetchBookingTaxAmount(); + // 将order元素的name属性设置为Order对象的name属性值 + base.setCurrencyCode(reader.getAttribute("currencyCode")); + base.setDecimals(reader.getAttribute("decimals")); + // 将order元素的txt值设置为Order对象的value值 + base.setTotalValue(reader.getValue()); + return base; + } +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTaxesAndFees.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTaxesAndFees.java new file mode 100644 index 0000000..1d16404 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTaxesAndFees.java @@ -0,0 +1,49 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("TaxesAndFees") +public class FetchBookingTaxesAndFees { + + @XStreamAsAttribute + @XStreamAlias("TotalCharges") + private String totalCharges; + + @XStreamAsAttribute + @XStreamAlias("decimals") + private String decimals; + + @XStreamImplicit(itemFieldName="Charges") + private List listCharges; + + public String getTotalCharges() { + return totalCharges; + } + + public void setTotalCharges(String totalCharges) { + this.totalCharges = totalCharges; + } + + public String getDecimals() { + return decimals; + } + + public void setDecimals(String decimals) { + this.decimals = decimals; + } + + public List getListCharges() { + return listCharges; + } + + public void setListCharges(List listCharges) { + this.listCharges = listCharges; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingText.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingText.java new file mode 100644 index 0000000..87bae54 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingText.java @@ -0,0 +1,17 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("Text") +public class FetchBookingText { + + @XStreamAsAttribute + @XStreamAlias("TextElement") + private String textElement; + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTimeSpan.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTimeSpan.java new file mode 100644 index 0000000..4340cc5 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTimeSpan.java @@ -0,0 +1,34 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("TimeSpan") +public class FetchBookingTimeSpan { + + @XStreamAlias("StartDate") + private String startDate; + + @XStreamAlias("EndDate") + private String endDate; + + public String getStartDate() { + return startDate; + } + + public void setStartDate(String startDate) { + this.startDate = startDate; + } + + public String getEndDate() { + return endDate; + } + + public void setEndDate(String endDate) { + this.endDate = endDate; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTotal.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTotal.java new file mode 100644 index 0000000..c2fc68b --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTotal.java @@ -0,0 +1,45 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; + +@XStreamAlias("Total") +@XStreamConverter(FetchBookingTotalConvert.class) +public class FetchBookingTotal { + + @XStreamAsAttribute + @XStreamAlias("currencyCode") + private String currencyCode; + + @XStreamAsAttribute + @XStreamAlias("decimals") + private String decimals; + + private String totalValue; + + public String getCurrencyCode() { + return currencyCode; + } + + public void setCurrencyCode(String currencyCode) { + this.currencyCode = currencyCode; + } + + public String getDecimals() { + return decimals; + } + + public void setDecimals(String decimals) { + this.decimals = decimals; + } + + public String getTotalValue() { + return totalValue; + } + + public void setTotalValue(String totalValue) { + this.totalValue = totalValue; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTotalConvert.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTotalConvert.java new file mode 100644 index 0000000..b811d7b --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingTotalConvert.java @@ -0,0 +1,39 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +public class FetchBookingTotalConvert implements Converter { + //转换条件 + @Override + public boolean canConvert(Class type) { + return type.equals(FetchBookingTotal.class); + } + /** + * 将java对象转为xml时使用 + */ + @Override + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + FetchBookingTotal base = (FetchBookingTotal) source; + writer.addAttribute("currencyCode", base.getCurrencyCode()); + writer.addAttribute("decimals", base.getDecimals()); + writer.setValue(base.getTotalValue()); + } + /** + * 将xml转为java对象使用 + */ + @Override + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + // 在解析order元素时,先创建一个Order对象 + FetchBookingTotal base = new FetchBookingTotal(); + // 将order元素的name属性设置为Order对象的name属性值 + base.setCurrencyCode(reader.getAttribute("currencyCode")); + base.setDecimals(reader.getAttribute("decimals")); + // 将order元素的txt值设置为Order对象的value值 + base.setTotalValue(reader.getValue()); + return base; + } +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingUniqueID.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingUniqueID.java new file mode 100644 index 0000000..7b4d3ac --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingUniqueID.java @@ -0,0 +1,44 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; + +@XStreamAlias("UniqueID") +@XStreamConverter(FetchBookingUniqueIDConvert.class) +public class FetchBookingUniqueID { + + @XStreamAsAttribute + @XStreamAlias("type") + private String type; + + @XStreamAsAttribute + @XStreamAlias("source") + private String source; + + private String thisValue; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } + + public String getThisValue() { + return thisValue; + } + + public void setThisValue(String thisValue) { + this.thisValue = thisValue; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingUniqueIDConvert.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingUniqueIDConvert.java new file mode 100644 index 0000000..5ccd465 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingUniqueIDConvert.java @@ -0,0 +1,39 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +public class FetchBookingUniqueIDConvert implements Converter { + //转换条件 + @Override + public boolean canConvert(Class type) { + return type.equals(FetchBookingUniqueID.class); + } + /** + * 将java对象转为xml时使用 + */ + @Override + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + FetchBookingUniqueID base = (FetchBookingUniqueID) source; + writer.addAttribute("type", base.getType()); + writer.addAttribute("source", base.getSource()); + writer.setValue(base.getThisValue()); + } + /** + * 将xml转为java对象使用 + */ + @Override + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + // 在解析order元素时,先创建一个Order对象 + FetchBookingUniqueID base = new FetchBookingUniqueID(); + // 将order元素的name属性设置为Order对象的name属性值 + base.setType(reader.getAttribute("type")); + base.setSource(reader.getAttribute("source")); + // 将order元素的txt值设置为Order对象的value值 + base.setThisValue(reader.getValue()); + return base; + } +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingUniqueIDList.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingUniqueIDList.java new file mode 100644 index 0000000..ba936bb --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingUniqueIDList.java @@ -0,0 +1,22 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("UniqueIDList") +public class FetchBookingUniqueIDList { + + @XStreamImplicit(itemFieldName="UniqueID") + private List listUniqueID; + + public List getListUniqueID() { + return listUniqueID; + } + + public void setListUniqueID(List listUniqueID) { + this.listUniqueID = listUniqueID; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingUserDefinedValue.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingUserDefinedValue.java new file mode 100644 index 0000000..70643fc --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingUserDefinedValue.java @@ -0,0 +1,48 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("UserDefinedValue") +public class FetchBookingUserDefinedValue { + + @XStreamAsAttribute + @XStreamAlias("valueName") + private String valueName; + + @XStreamAlias("CharacterValue") + private String characterValue; + + @XStreamAlias("DateValue") + private String datevalue; + + public String getValueName() { + return valueName; + } + + public void setValueName(String valueName) { + this.valueName = valueName; + } + + public String getCharacterValue() { + return characterValue; + } + + public void setCharacterValue(String characterValue) { + this.characterValue = characterValue; + } + + public String getDatevalue() { + return datevalue; + } + + public void setDatevalue(String datevalue) { + this.datevalue = datevalue; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingUserDefinedValues.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingUserDefinedValues.java new file mode 100644 index 0000000..465cfe9 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FetchBookingUserDefinedValues.java @@ -0,0 +1,24 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + +@XStreamAlias("UserDefinedValues") +public class FetchBookingUserDefinedValues { + + @XStreamImplicit(itemFieldName="UserDefinedValue") + private List userDefinedValue; + + public List getUserDefinedValue() { + return userDefinedValue; + } + + public void setUserDefinedValue(List userDefinedValue) { + this.userDefinedValue = userDefinedValue; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FutureBookingSummaryBase.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FutureBookingSummaryBase.java new file mode 100644 index 0000000..465ea48 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FutureBookingSummaryBase.java @@ -0,0 +1,46 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamConverter; + +@XStreamAlias("Base") +@XStreamConverter(FutureBookingSummaryBaseConvert.class) +public class FutureBookingSummaryBase { + + @XStreamAsAttribute + @XStreamAlias("currencyCode") + private String currencyCode; + + @XStreamAsAttribute + @XStreamAlias("decimals") + private String decimals; + + private String baseValue; + + public String getCurrencyCode() { + return currencyCode; + } + + public void setCurrencyCode(String currencyCode) { + this.currencyCode = currencyCode; + } + + public String getDecimals() { + return decimals; + } + + public void setDecimals(String decimals) { + this.decimals = decimals; + } + + public String getBaseValue() { + return baseValue; + } + + public void setBaseValue(String baseValue) { + this.baseValue = baseValue; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FutureBookingSummaryBaseConvert.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FutureBookingSummaryBaseConvert.java new file mode 100644 index 0000000..fe9418e --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FutureBookingSummaryBaseConvert.java @@ -0,0 +1,39 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.MarshallingContext; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + +public class FutureBookingSummaryBaseConvert implements Converter { + //转换条件 + @Override + public boolean canConvert(Class type) { + return type.equals(FutureBookingSummaryBase.class); + } + /** + * 将java对象转为xml时使用 + */ + @Override + public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { + FutureBookingSummaryBase base = (FutureBookingSummaryBase) source; + writer.addAttribute("currencyCode", base.getCurrencyCode()); + writer.addAttribute("decimals", base.getDecimals()); + writer.setValue(base.getBaseValue()); + } + /** + * 将xml转为java对象使用 + */ + @Override + public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + // 在解析order元素时,先创建一个Order对象 + FutureBookingSummaryBase base = new FutureBookingSummaryBase(); + // 将order元素的name属性设置为Order对象的name属性值 + base.setCurrencyCode(reader.getAttribute("currencyCode")); + base.setDecimals(reader.getAttribute("decimals")); + // 将order元素的txt值设置为Order对象的value值 + base.setBaseValue(reader.getValue()); + return base; + } +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/FutureBookingSummaryRate.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FutureBookingSummaryRate.java new file mode 100644 index 0000000..5c257b3 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/FutureBookingSummaryRate.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + +@XStreamAlias("Rate") +public class FutureBookingSummaryRate { + + @XStreamAsAttribute + @XStreamAlias("Base") + private FutureBookingSummaryBase base; + + public FutureBookingSummaryBase getBase() { + return base; + } + + public void setBase(FutureBookingSummaryBase base) { + this.base = base; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/GuestRequestsRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/GuestRequestsRequest.java new file mode 100644 index 0000000..e1d1799 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/GuestRequestsRequest.java @@ -0,0 +1,166 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.namespace.QName; +import jakarta.xml.soap.SOAPMessage; + +import com.mgm.mcrm.basesetting.property.models.CfgProperties; +import com.mgm.mcrm.booking.dtos.opera.schema.Comment; +import com.mgm.mcrm.booking.dtos.opera.schema.ConfirmationNumber; +import com.mgm.mcrm.booking.dtos.opera.schema.GuestRequest; +import com.mgm.mcrm.booking.dtos.opera.schema.GuestRequestMsg; +import com.mgm.mcrm.booking.dtos.opera.schema.HotelReference; +import com.mgm.mcrm.booking.dtos.opera.schema.OGHeader; +import com.mgm.mcrm.booking.dtos.opera.schema.SpecialRequest; +import com.mgm.mcrm.booking.dtos.opera.schema.Trace; +import com.mgm.mcrm.common.utils.SOAPUtil; +import lombok.Data; + +@Data +public class GuestRequestsRequest { + + private String transactionID; + private String timeStamp; + private CfgProperties property; + private StringBuffer requestString; + private String confirmationNo; + private String fullOverlay = "N"; + private String comment; + private String actionType; + private String commentType; + private String traceComment; + private String traceDate; + private Long commentId; + private List specialRequests; + + public GuestRequestsRequest() { + } + + public StringBuffer getRequestString() { + this.requestString = new StringBuffer(); + this.requestString.append(""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "+this.confirmationNo+""); + if(this.comment!=null) { + this.requestString.append(" ADD"); + this.requestString.append(" COMMENTS"); + this.requestString.append(" "+this.fullOverlay+""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "+this.comment+""); + if(this.commentType!=null) { + this.requestString.append(" "+this.commentType+""); + } + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + }else if(this.traceComment!=null){ + this.requestString.append(" ADD"); + this.requestString.append(" TRACES"); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "+this.traceComment+""); + this.requestString.append(" "+this.traceDate+""); +// this.requestString.append(" 09:00:00"); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + }else { + if(specialRequests!=null && specialRequests.size()>0) { + this.requestString.append(" "+this.actionType+""); + this.requestString.append(" SPECIALS"); + this.requestString.append(" "+this.fullOverlay+""); + this.requestString.append(" "); + this.requestString.append(" "); + for(int i=0;i"); + } + this.requestString.append(" "); + this.requestString.append(" "); + } + } + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(""); + + return this.requestString; + } + + public SOAPMessage buildRequestMessage() { + SOAPMessage soapMessage = null; + try { + List qNameList = new ArrayList(); + qNameList.add(new QName("http://webservices.micros.com/ows/5.1/Reservation.wsdl", "", "ns1")); + qNameList.add(new QName("http://webservices.micros.com/og/4.3/HotelCommon/", "", "hc")); + qNameList.add(new QName("http://webservices.micros.com/og/4.3/Core/", "", "ns3")); + GuestRequestMsg msgData = new GuestRequestMsg(); + OGHeader msgHeader = new OGHeader(); + msgHeader.setTransactionID(this.transactionID); + msgHeader.setTimeStamp(this.timeStamp+"+08:00"); + ConfirmationNumber bookingNo = new ConfirmationNumber(); + bookingNo.setValue(this.confirmationNo); + msgData.setConfirmationNo(bookingNo); + HotelReference hotelRef = new HotelReference(); + if(this.getProperty()!=null) { + hotelRef.setHotelCode(this.getProperty().getCode()); + } + msgData.setHotelReference(hotelRef); + List gRequests = new ArrayList<>(); + GuestRequest reqObj = new GuestRequest(); + if(this.comment!=null) { + msgData.setActionType("ADD"); + msgData.setFullOverlay(this.fullOverlay); + msgData.setRequestType("COMMENTS"); + List comments = new ArrayList(); + Comment reqComment = new Comment(); + reqComment.setCommentType(this.commentType); + reqComment.setText(this.comment); + comments.add(reqComment); + reqObj.setComments(comments); + }else if(this.traceComment!=null) { + msgData.setActionType("ADD"); + msgData.setFullOverlay(null); + msgData.setRequestType("TRACES"); + List traces = new ArrayList(); + Trace reqTrace = new Trace(); + reqTrace.setText(this.traceComment); + reqTrace.setTraceDate(this.traceDate); + traces.add(reqTrace); + reqObj.setTraces(traces); + }else if(specialRequests!=null && specialRequests.size()>0) { + msgData.setActionType(this.actionType); + msgData.setFullOverlay(this.fullOverlay); + msgData.setRequestType("SPECIALS"); + List specRequests = new ArrayList(); + for(int i=0;i"); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "+this.getNameId()+""); + this.requestString.append(" "); + this.requestString.append(" "+this.getPlayerId()+""); + this.requestString.append(" GP"); + this.requestString.append(" "+this.getMemberName()+""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(""); + + return this.requestString; + } + + public String getTransactionID() { + return transactionID; + } + + public void setTransactionID(String transactionID) { + this.transactionID = transactionID; + } + + public String getTimeStamp() { + return timeStamp; + } + + public void setTimeStamp(String timeStamp) { + this.timeStamp = timeStamp; + } + + public String getNameId() { + return nameId; + } + + public void setNameId(String nameId) { + this.nameId = nameId; + } + + public String getPlayerId() { + return playerId; + } + + public void setPlayerId(String playerId) { + this.playerId = playerId; + } + + public String getMemberName() { + return memberName; + } + + public void setMemberName(String memberName) { + this.memberName = memberName; + } + + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/InsertGuestCardResponse.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/InsertGuestCardResponse.java new file mode 100644 index 0000000..acbd56e --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/InsertGuestCardResponse.java @@ -0,0 +1,35 @@ +package com.mgm.mcrm.booking.dtos.opera; +import java.io.Serializable; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("InsertGuestCardResponse") +public class InsertGuestCardResponse implements Serializable { + + + @XStreamAlias("Result") + private CancelBookingResult result; + + + + + public InsertGuestCardResponse() { + + } + + + public CancelBookingResult getResult() { + return result; + } + + + public void setResult(CancelBookingResult result) { + this.result = result; + } + + + + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/ModifyBookingRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/ModifyBookingRequest.java new file mode 100644 index 0000000..4832a42 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/ModifyBookingRequest.java @@ -0,0 +1,182 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.alibaba.fastjson.JSONObject; + +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.basesetting.property.models.CfgProperties; +import com.mgm.mcrm.common.utils.DateTimeUtil; +import lombok.Data; + +@Data +public class ModifyBookingRequest{ + + private StringBuffer requestString; + private Bookings booking; + private String bookBy; + private String transactionID; + private String timeStamp; + private CfgProperties property; + private StringBuffer requestHeader; + private String eta; + private String miscCharge; + + public StringBuffer getRequestString() { + this.requestString = new StringBuffer(); + this.requestString.append(""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "+this.booking.getConfirmationNo()+""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + if(this.booking.getBookingRates()!=null&&this.booking.getBookingRates().size()>0) { + this.requestString.append(" "); + for(int i=0;i"); + this.requestString.append(" "+rates.get("rate")+""); + this.requestString.append(" "); + } + this.requestString.append(" "); + } + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "+DateTimeUtil.getDateByFormat(this.booking.getCheckinDate(), "yyyy-MM-dd")+""); + this.requestString.append(" "+DateTimeUtil.getDateByFormat(this.booking.getCheckoutDate(), "yyyy-MM-dd")+""); + this.requestString.append(" "); +// this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" Y"); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(""); + return this.requestString; + } + + public StringBuffer getRequestMisChargeString() { + this.requestString = new StringBuffer(); + this.requestString.append(""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "+this.booking.getConfirmationNo()+""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + if(this.booking.getBookingRates()!=null&&this.booking.getBookingRates().size()>0) { + this.requestString.append(" "); + for(int i=0;i"); + this.requestString.append(" "+rates.get("rate")+""); + this.requestString.append(" "); + } + this.requestString.append(" "); + } + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "+miscCharge+""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(""); + return this.requestString; + } + + public StringBuffer getRequestETAString() { + this.requestString = new StringBuffer(); + this.requestString.append(""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "+this.booking.getConfirmationNo()+""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(""); + return this.requestString; + } + + public StringBuffer getRequestChangeDateString() { + this.requestString = new StringBuffer(); + this.requestString.append(""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "+this.booking.getConfirmationNo()+""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "+DateTimeUtil.getDateByFormat(this.booking.getCheckinDate(), "yyyy-MM-dd")+"T00:00:00.0000000-05:00"); + this.requestString.append(" "+DateTimeUtil.getDateByFormat(this.booking.getCheckoutDate(), "yyyy-MM-dd")+"T00:00:00.0000000-05:00"); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(""); + return this.requestString; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/ModifyBookingResponse.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/ModifyBookingResponse.java new file mode 100644 index 0000000..d848e70 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/ModifyBookingResponse.java @@ -0,0 +1,12 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("ModifyBookingResponse") +public class ModifyBookingResponse extends CreateBookingResponse { + + public ModifyBookingResponse() { + + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/UpdatePassportRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/UpdatePassportRequest.java new file mode 100644 index 0000000..37ca6d6 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/UpdatePassportRequest.java @@ -0,0 +1,69 @@ +package com.mgm.mcrm.booking.dtos.opera; + +import java.util.List; + +public class UpdatePassportRequest { + + private String transactionID; + private String timeStamp; + private StringBuffer requestString; + private String nameId; + private String number; + + public UpdatePassportRequest() { + } + + public StringBuffer getRequestString() { + this.requestString = new StringBuffer(); + this.requestString.append(""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "+this.getNameId()+""); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(" "); + this.requestString.append(""); + + return this.requestString; + } + + public String getTransactionID() { + return transactionID; + } + + public void setTransactionID(String transactionID) { + this.transactionID = transactionID; + } + + public String getTimeStamp() { + return timeStamp; + } + + public void setTimeStamp(String timeStamp) { + this.timeStamp = timeStamp; + } + + public String getNameId() { + return nameId; + } + + public void setNameId(String nameId) { + this.nameId = nameId; + } + + public String getNumber() { + return number; + } + + public void setNumber(String number) { + this.number = number; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/UpdatePassportResponse.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/UpdatePassportResponse.java new file mode 100644 index 0000000..4595888 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/UpdatePassportResponse.java @@ -0,0 +1,35 @@ +package com.mgm.mcrm.booking.dtos.opera; +import java.io.Serializable; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + +@XStreamAlias("UpdatePassportResponse") +public class UpdatePassportResponse implements Serializable { + + + @XStreamAlias("Result") + private CancelBookingResult result; + + + + + public UpdatePassportResponse() { + + } + + + public CancelBookingResult getResult() { + return result; + } + + + public void setResult(CancelBookingResult result) { + this.result = result; + } + + + + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/Comment.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/Comment.java new file mode 100644 index 0000000..f898ed2 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/Comment.java @@ -0,0 +1,41 @@ +package com.mgm.mcrm.booking.dtos.opera.schema; + +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; +import jakarta.xml.bind.annotation.XmlType; + +@XmlRootElement(name="Comment", namespace="http://webservices.micros.com/og/4.3/HotelCommon/") +@XmlType(propOrder = { + "text", + "commentType" + }) +public class Comment { + + private boolean guestViewable=true; + private String text; + private String commentType; + + @XmlAttribute + public boolean isGuestViewable() { + return guestViewable; + } + public void setGuestViewable(boolean guestViewable) { + this.guestViewable = guestViewable; + } + @XmlElement(name="Text", namespace="http://webservices.micros.com/og/4.3/HotelCommon/") + public String getText() { + return text; + } + public void setText(String text) { + this.text = text; + } + @XmlElement(name="CommonType", namespace="http://webservices.micros.com/og/4.3/HotelCommon/") + public String getCommentType() { + return commentType; + } + public void setCommentType(String commentType) { + this.commentType = commentType; + } +} + diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/ConfirmationNumber.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/ConfirmationNumber.java new file mode 100644 index 0000000..f3fc690 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/ConfirmationNumber.java @@ -0,0 +1,32 @@ +package com.mgm.mcrm.booking.dtos.opera.schema; + +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlRootElement; +import jakarta.xml.bind.annotation.XmlValue; + +@XmlRootElement +public class ConfirmationNumber { + + private String type="INTERNAL"; + private String value; + + @XmlAttribute + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + @XmlValue + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/GuestRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/GuestRequest.java new file mode 100644 index 0000000..da0e346 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/GuestRequest.java @@ -0,0 +1,52 @@ +package com.mgm.mcrm.booking.dtos.opera.schema; + +import java.util.List; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlElementWrapper; +import jakarta.xml.bind.annotation.XmlRootElement; +import jakarta.xml.bind.annotation.XmlType; + +@XmlRootElement(name="GuestRequestsRequest",namespace="http://webservices.micros.com/og/4.3/HotelCommon/") +@XmlType(propOrder = { + "comments", + "traces", + "specials" + }) +public class GuestRequest { + + private List comments; + private List traces; + private List specials; + + @XmlElement(name = "Comment",namespace="http://webservices.micros.com/og/4.3/HotelCommon/") + @XmlElementWrapper(name="Comments",namespace="http://webservices.micros.com/og/4.3/HotelCommon/") + public List getComments() { + return comments; + } + + public void setComments(List comments) { + this.comments = comments; + } + + @XmlElement(name = "Trace",namespace="http://webservices.micros.com/og/4.3/HotelCommon/") + @XmlElementWrapper(name="Traces",namespace="http://webservices.micros.com/og/4.3/HotelCommon/") + public List getTraces() { + return traces; + } + + public void setTraces(List traces) { + this.traces = traces; + } + + @XmlElement(name = "SpecialRequest",namespace="http://webservices.micros.com/og/4.3/HotelCommon/") + @XmlElementWrapper(name="Specials",namespace="http://webservices.micros.com/og/4.3/HotelCommon/") + public List getSpecials() { + return specials; + } + + public void setSpecials(List specials) { + this.specials = specials; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/GuestRequestMsg.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/GuestRequestMsg.java new file mode 100644 index 0000000..5c2b0cc --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/GuestRequestMsg.java @@ -0,0 +1,82 @@ +package com.mgm.mcrm.booking.dtos.opera.schema; + +import java.util.List; + +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; +import jakarta.xml.bind.annotation.XmlType; + +@XmlRootElement(name="GuestRequestsRequest",namespace="http://webservices.micros.com/ows/5.1/Reservation.wsdl") +@XmlType(propOrder = { + "hotelReference", + "confirmationNo", + "actionType", + "requestType", + "fullOverlay", + "guestRequests"}) +public class GuestRequestMsg { + + private HotelReference hotelReference; + private ConfirmationNumber confirmationNo; + private String fullOverlay; + private String actionType; + private String requestType; + private List guestRequests; + + public GuestRequestMsg() { + } + @XmlElement(name="FullOverlay") + public String getFullOverlay() { + return fullOverlay; + } + + public void setFullOverlay(String fullOverlay) { + this.fullOverlay = fullOverlay; + } + + @XmlElement(name="ActionType") + public String getActionType() { + return actionType; + } + + public void setActionType(String actionType) { + this.actionType = actionType; + } + + @XmlElement(name="ConfirmationNumber") + public ConfirmationNumber getConfirmationNo() { + return confirmationNo; + } + + public void setConfirmationNo(ConfirmationNumber confirmationNo) { + this.confirmationNo = confirmationNo; + } + + @XmlElement(name="HotelReference") + public HotelReference getHotelReference() { + return hotelReference; + } + + public void setHotelReference(HotelReference hotelReference) { + this.hotelReference = hotelReference; + } + @XmlElement(name="RequestType") + public String getRequestType() { + return requestType; + } + + public void setRequestType(String requestType) { + this.requestType = requestType; + } + + @XmlElement(name = "GuestRequests") + public List getGuestRequests() { + return guestRequests; + } + + public void setGuestRequests(List guestRequests) { + this.guestRequests = guestRequests; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/HotelReference.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/HotelReference.java new file mode 100644 index 0000000..4547bd9 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/HotelReference.java @@ -0,0 +1,28 @@ +package com.mgm.mcrm.booking.dtos.opera.schema; + +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +public class HotelReference { + + private String chainCode="CA"; + private String hotelCode; + + @XmlAttribute + public String getChainCode() { + return chainCode; + } + public void setChainCode(String chainCode) { + this.chainCode = chainCode; + } + @XmlAttribute + public String getHotelCode() { + return hotelCode; + } + public void setHotelCode(String hotelCode) { + this.hotelCode = hotelCode; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/OGHeader.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/OGHeader.java new file mode 100644 index 0000000..730dab8 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/OGHeader.java @@ -0,0 +1,44 @@ +package com.mgm.mcrm.booking.dtos.opera.schema; + +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name="OGHeader",namespace="http://webservices.micros.com/og/4.3/Core/") +public class OGHeader { + + private boolean channelValidation=false; + private String timeStamp; + private String primaryLangID="E"; + private String transactionID; + + + @XmlAttribute + public String getTransactionID() { + return transactionID; + } + public void setTransactionID(String transactionID) { + this.transactionID = transactionID; + } + @XmlAttribute + public String getTimeStamp() { + return timeStamp; + } + public void setTimeStamp(String timeStamp) { + this.timeStamp = timeStamp; + } + @XmlAttribute + public String getPrimaryLangID() { + return primaryLangID; + } + public void setPrimaryLangID(String primaryLangID) { + this.primaryLangID = primaryLangID; + } + + @XmlAttribute + public boolean isChannelValidation() { + return channelValidation; + } + public void setChannelValidation(boolean channelValidation) { + this.channelValidation = channelValidation; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/SpecialRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/SpecialRequest.java new file mode 100644 index 0000000..82ac1d6 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/SpecialRequest.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.booking.dtos.opera.schema; + +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name="SpecialRequest", namespace="http://webservices.micros.com/og/4.3/HotelCommon/") +public class SpecialRequest { + + private String requestCode; + + @XmlAttribute + public String getRequestCode() { + return requestCode; + } + + public void setRequestCode(String requestCode) { + this.requestCode = requestCode; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/Trace.java b/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/Trace.java new file mode 100644 index 0000000..25ab30c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/opera/schema/Trace.java @@ -0,0 +1,42 @@ +package com.mgm.mcrm.booking.dtos.opera.schema; + +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; +import jakarta.xml.bind.annotation.XmlType; + +@XmlRootElement(name="Trace", namespace="http://webservices.micros.com/og/4.3/HotelCommon/") +@XmlType(propOrder = { + "text", + "traceDate" + }) +public class Trace { + + private String department="FO"; + private String text; + private String traceDate; + + @XmlAttribute + public String getDepartment() { + return department; + } + public void setDepartment(String department) { + this.department = department; + } + @XmlElement(name="Text", namespace="http://webservices.micros.com/og/4.3/HotelCommon/") + public String getText() { + return text; + } + public void setText(String text) { + this.text = text; + } + @XmlElement(name="TraceDate", namespace="http://webservices.micros.com/og/4.3/HotelCommon/") + public String getTraceDate() { + return traceDate; + } + public void setTraceDate(String traceDate) { + this.traceDate = traceDate; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/search/BookingQueryRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/search/BookingQueryRequest.java new file mode 100644 index 0000000..af0bc65 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/search/BookingQueryRequest.java @@ -0,0 +1,29 @@ +package com.mgm.mcrm.booking.dtos.search; + +import com.mgm.mcrm.common.dtos.BaseQueryRequest; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +public class BookingQueryRequest extends BaseQueryRequest { + private String searchName; + private String searchType; + private String searchPlayerId; + private String searchBookerId; + private String searchApproverName; + private String searchBookerName; + private String searchBookerTeam; + private String searchConfirmationNo; + private String searchStatus; + private Long searchPropertyId; + private List searchBookDate; + private List searchCheckInDate; + private List searchApproverDate; + private String permissionId; + private String permissionGroup; + private List searchRoomId; + private List searchRoomTypeId; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/search/BookingSearchRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/search/BookingSearchRequest.java new file mode 100644 index 0000000..5ff559f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/search/BookingSearchRequest.java @@ -0,0 +1,11 @@ +package com.mgm.mcrm.booking.dtos.search; + +import com.mgm.mcrm.common.dtos.mgm_api.PlayerProfileEntry; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +public class BookingSearchRequest { + @NotNull + private PlayerProfileEntry member; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/search/CheckSecondTPDRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/search/CheckSecondTPDRequest.java new file mode 100644 index 0000000..748c354 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/search/CheckSecondTPDRequest.java @@ -0,0 +1,15 @@ +package com.mgm.mcrm.booking.dtos.search; + +import lombok.Data; + +import java.util.List; + +@Data +public class CheckSecondTPDRequest { + private String playerId; + private String roomCat; + private String bookingType; + private String property; + private List dates; + private List dateRange; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/search/CheckTPDRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/search/CheckTPDRequest.java new file mode 100644 index 0000000..1020129 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/search/CheckTPDRequest.java @@ -0,0 +1,14 @@ +package com.mgm.mcrm.booking.dtos.search; + +import lombok.Data; + +import java.util.List; + +@Data +public class CheckTPDRequest { + private String playerId; + private String roomCat; + private String bookingType; + private String property; + List dates; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/search/DateRange.java b/src/main/java/com/mgm/mcrm/booking/dtos/search/DateRange.java new file mode 100644 index 0000000..b0f35cd --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/search/DateRange.java @@ -0,0 +1,17 @@ +package com.mgm.mcrm.booking.dtos.search; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class DateRange { + + @JsonProperty("StartDate") + private String startDate; + + @JsonProperty("EndDate") + private String endDate; + + @JsonProperty("RoomBookingOrdinalNumber") + private int roomBookingOrdinalNumber; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/search/GetBookingByGroupRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/search/GetBookingByGroupRequest.java new file mode 100644 index 0000000..241a6f0 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/search/GetBookingByGroupRequest.java @@ -0,0 +1,8 @@ +package com.mgm.mcrm.booking.dtos.search; + +import lombok.Data; + +@Data +public class GetBookingByGroupRequest { + private String groupId; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/search/GetBookingByIdRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/search/GetBookingByIdRequest.java new file mode 100644 index 0000000..e006d19 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/search/GetBookingByIdRequest.java @@ -0,0 +1,8 @@ +package com.mgm.mcrm.booking.dtos.search; + +import lombok.Data; + +@Data +public class GetBookingByIdRequest { + private Long id; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/search/GetBookingByNameIdRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/search/GetBookingByNameIdRequest.java new file mode 100644 index 0000000..cdb50bc --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/search/GetBookingByNameIdRequest.java @@ -0,0 +1,14 @@ +package com.mgm.mcrm.booking.dtos.search; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class GetBookingByNameIdRequest { + private Integer startIndex; + private Integer pageSize; + private List nameId; + +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/search/GetOperaBookingRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/search/GetOperaBookingRequest.java new file mode 100644 index 0000000..55c937d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/search/GetOperaBookingRequest.java @@ -0,0 +1,8 @@ +package com.mgm.mcrm.booking.dtos.search; + +import lombok.Data; + +@Data +public class GetOperaBookingRequest { + private String conf; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/search/PlayerLookupRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/search/PlayerLookupRequest.java new file mode 100644 index 0000000..71d98bb --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/search/PlayerLookupRequest.java @@ -0,0 +1,8 @@ +package com.mgm.mcrm.booking.dtos.search; + +import lombok.Data; + +@Data +public class PlayerLookupRequest { + private String playerId; +} diff --git a/src/main/java/com/mgm/mcrm/booking/dtos/search/WebRecordSearchRequest.java b/src/main/java/com/mgm/mcrm/booking/dtos/search/WebRecordSearchRequest.java new file mode 100644 index 0000000..c6122d0 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/dtos/search/WebRecordSearchRequest.java @@ -0,0 +1,12 @@ +package com.mgm.mcrm.booking.dtos.search; + +import com.mgm.mcrm.common.dtos.mgm_api.PlayerProfileEntry; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +public class WebRecordSearchRequest { + @NotNull + private PlayerProfileEntry member; + private String userId; +} diff --git a/src/main/java/com/mgm/mcrm/booking/enums/ProfileTierEnums.java b/src/main/java/com/mgm/mcrm/booking/enums/ProfileTierEnums.java new file mode 100644 index 0000000..3787fcc --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/enums/ProfileTierEnums.java @@ -0,0 +1,45 @@ +package com.mgm.mcrm.booking.enums; + +import lombok.Getter; + +public enum ProfileTierEnums { + + GOLD("GOLD", "GLC_GOLD"), + PLATINUM_NG("PLATINUM NG", "MLIFE_PLAT"), + NOIR("NOIR", "MLIFE_NOIR"), + PEARL("PEARL", "MLIFE_PEARL"), + SAPPHIRE("SAPPHIRE", "MLIFE_SAPPHIRE"), + SUPREME("SUPREME", "GLC_SUPREME"), + PLATINUM("PLATINUM", "GLC_PLATINUM"), + PLATINUM_IM("PLATINUM IM", "IM_PLAT"), + ELITE("ELITE", "GLC_ELITE"), + ELITE_IM("ELITE IM", "IM_ELITE"), + SUPREME_88("SUPREME 88", "GLC_S88"), + SUPREME_88_IM("SUPREME 88 IM", "IM_S88"), + ALPHA("ALPHA", "GLC_ALPHA"), + ALPHA_IM("ALPHA IM", "IM_ALPHA"), + PRIDE_1("Pride 1", "PRIDE_1"), + PRIDE_2("Pride 2", "PRIDE_2"); + + @Getter + private final String igtPMLevel; + + @Getter + private final String daylightLevel; + + ProfileTierEnums(String igtPMLevel, String daylightLevel) { + this.igtPMLevel = igtPMLevel; + this.daylightLevel = daylightLevel; + } + + public static String fromIgtPMLevel(String igtPMLevel) { + + for (ProfileTierEnums profileTierEnums : values()) { + if (profileTierEnums.igtPMLevel.equalsIgnoreCase(igtPMLevel)) { + return profileTierEnums.daylightLevel; + } + } + + return null; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/mappers/BookingMapper.java b/src/main/java/com/mgm/mcrm/booking/mappers/BookingMapper.java new file mode 100644 index 0000000..c643b1e --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/mappers/BookingMapper.java @@ -0,0 +1,89 @@ +package com.mgm.mcrm.booking.mappers; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.mgm.mcrm.booking.dtos.BookingDateEntry; +import com.mgm.mcrm.booking.dtos.BookingDto; +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.booking.models.BookingsView; +import com.mgm.mcrm.common.dtos.mgm_api.PlayerProfileEntry; +import com.mgm.mcrm.player.dtos.request.TodoChangeDateRequest; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; + +import java.util.List; + +@Mapper(componentModel = "spring") +public interface BookingMapper { + + List viewToBookingDtoList(List list); + + @Mapping(target = "sharerList", source = "sharer", qualifiedByName = "jsonToSharerList") + BookingDto viewToBookingDto(BookingsView booking); + + @Mapping(target = "dateList", source = "dateList", qualifiedByName = "jsonToDateList") + @Mapping(target = "member", source = "member", qualifiedByName = "jsonToMember") + @Mapping(target = "sharerList", source = "sharer", qualifiedByName = "jsonToSharerList") + BookingDto entityToDto(Bookings booking); + + @Mapping(target = "dateList", source = "dateList", qualifiedByName = "dateListToJson") + @Mapping(target = "member", source = "member", qualifiedByName = "memberToJson") + Bookings dtoToBooking(BookingDto booking); + + List toBookingList(List list); + + @Named("dateListToJson") + default String convertDateListToJson(List dateList){ + if (dateList == null) { + return null; + } + return JSONArray.toJSONString(dateList); + } + + @Named("jsonToDateList") + default List convertJsonToDateList(String jsonContent){ + if (jsonContent == null) { + return null; + } + return JSONArray.parseArray(jsonContent,BookingDateEntry.class); + } + + @Named("sharerListToJson") + default String convertSharerListToJson(JSONArray shareList){ + if (shareList == null) { + return null; + } + return JSONArray.toJSONString(shareList); + } + + @Named("jsonToSharerList") + default JSONArray convertJsonToSharerList(String jsonContent){ + if (jsonContent == null) { + return null; + } + return JSONArray.parseArray(jsonContent); + } + + @Named("memberToJson") + default String convertMemberToJson(PlayerProfileEntry member){ + if (member == null) { + return null; + } + return JSONObject.toJSONString(member); + } + + @Named("jsonToMember") + default PlayerProfileEntry convertJsonToMember(String jsonContent){ + if (jsonContent == null) { + return null; + } + return JSONObject.parseObject(jsonContent, PlayerProfileEntry.class); + } + + @Mapping(target = "sharerList", source = "sharer", qualifiedByName = "jsonToSharerList") + @Mapping(target = "dateList", ignore = true) + BookingDto changeDateRequestToDto(TodoChangeDateRequest request); + + TodoChangeDateRequest bookingDtoToChangeRequest(BookingDto param); +} diff --git a/src/main/java/com/mgm/mcrm/booking/models/Bookings.java b/src/main/java/com/mgm/mcrm/booking/models/Bookings.java new file mode 100644 index 0000000..e6ac8b1 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/models/Bookings.java @@ -0,0 +1,222 @@ +package com.mgm.mcrm.booking.models; + +import java.io.Serializable; +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.Transient; + +import com.alibaba.fastjson.JSONArray; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +@Data +@Entity +@Table(name="bookings") +public class Bookings implements Serializable { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="revision_of") + private Long revisionOf; + @Column(name="confirmation_no") + private String confirmationNo; + @Column(name="resv_id") + private String resvId; + @Column(name="last_opera_status") + private String lastOperaStatus; + @Column(name="player_id") + private String playerId; + @Column(name="member_title") + private String memberTitle; + @Column(name="member_first_name") + private String memberFirstName; + @Column(name="member_last_name") + private String memberLastName; + @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") + @Column(name="checkin_date") + private Date checkinDate; + @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") + @Column(name="checkout_date") + private Date checkoutDate; + @Column(name="property_id") + private Long propertyId; + @Column(name="room_type_id") + private Long roomTypeId; + @Column(name="dl_profile_id") + private String dlProfileId; + @Column(name="notify_language") + private String notifyLanguage; + @Column(name="payment_amount") + private Double paymentAmount; + @Column(name="opera_total") + private Double operaTotal; + @Column(name="comment") + private String comment; + @Column(name="rate_plan_code") + private String ratePlanCode; + @Column(name="chain_code") + private String chainCode; + @Column(name="hotel_code") + private String hotelCode; + @Column(name="room_type_code") + private String roomTypeCode; + @Column(name="promotion_code") + private String promotionCode; + @Column(name="dl_guarantee_type_id") + private String dlGuaranteeTypeId; + @Column(name="payment_type") + private String paymentType; + @Column(name="market_code") + private String marketCode; + @Column(name="dl_source_id") + private String dlSourceId; + @Column(name="cancelled_by") + private String cancelledBy; + @Column(name="cancelled_at") + private Date cancelledAt; + @Column(name="section_id") + private Long sectionId; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + @Column(name="created_at") + private Date createdAt; + @Column(name="created_by") + private String createdBy; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + @Column(name="updated_at") + private Date updatedAt; + @Column(name="updated_by") + private String updatedBy; + @Column(name="approve_status") + private String approveStatus; + @Column(name="remark") + private String remark; + @Column(name="book_type") + private String bookType; + @Column(name="dl_block_id") + private String dlBlockId; + @Column(name="num_of_night") + private Integer numOfNight; + @Column(name="section_name") + private String sectionName; + @Column(name="booker") + private String booker; + @Column(name="msc_remark") + private String mscRemark; + @Column(name="approval_remark") + private String approvalRemark; + @Column(name="room") + private String room; + @Column(name="sharer") + private String sharer; + @Column(name="date_list") + private String dateList; + @Column(name="feature_code") + private String featureCode; + @Column(name="item_code") + private String itemCode; + @Column(name="group_id") + private String groupId; + @Column(name="bed_type_master_group_id") + private Long bedTypeMasterGroupId; + @Column(name="bed_type_name") + private String bedTypeName; + @Column(name="created_by_name") + private String createdByName; + @Column(name="room_id") + private Long roomId; + @Column(name="block_id") + private Long blockId; + @Column(name="try_time") + private Integer tryTime; + @Column(name="error_message") + private String errorMessage; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + @Column(name="failed_at") + private Date failedAt; + @Column(name="process_status") + private Integer processStatus; + @Column(name="booking_type_id") + private Long bookingTypeId; + @Column(name="member") + private String member; + @Column(name="failed_room_type") + private String failedRoomType; + @Column(name="approved_by") + private String approvedBy; + @Column(name="approved_at") + private Date approvedAt; + @Column(name="waitlist_id") + private Long waitlistId; + @Column(name="segment_id") + private Long segmentId; + @Column(name="other_room_status_id") + private Long otherRoomStatusId; + @Column(name="other_follow_up_status_id") + private Long otherFollowUpStatusId; + @Column(name="approved_id") + private Long approvedId; + @Column(name="requested_co_date") + private Date requestedCoDate; + @Column(name="eta") + private String eta; + @Column(name="change_checkin_date") + private String changeCheckinDate; + @Column(name="change_checkout_date") + private String changeCheckoutDate; + @Column(name="dl_channel_id") + private String dlChannelId; + @Column(name="dl_account_id") + private String dlAccountId; + @Column(name="dl_reservation_id") + private String dlReservationId; + @Column(name="opera_profile_id") + private Long operaProfileId; + @Column(name = "dl_purchase_element_id") + private String dlPurchaseElementId; + + @Column(name = "block_code") + private String blockCode; + + @Column(name = "misc_charge") + private String miscCharge; + + @Column(name = "category") + private String category; + @Column(name = "source_code") + private String sourceCode; + + @Column(name = "guarantee_type") + private String guaranteeType; + + @Column(name = "opera_comment") + private String operaComment; + + @Column(name = "opera_comment_id") + private Long operaCommentId; + + @Column(name = "dl_external_no") + private String dlExternalNo; + + @Column(name = "approval_booking_id") + private String approvalBookingId; + + @Column(name = "approval_reason") + private String approvalReason; + + @Column(name = "fail_platform") + private String failPlatform; + + @Transient + private String status; + @Transient + private Long pendingRevisionId; + @Transient + private JSONArray bookingRates; +} diff --git a/src/main/java/com/mgm/mcrm/booking/models/BookingsView.java b/src/main/java/com/mgm/mcrm/booking/models/BookingsView.java new file mode 100644 index 0000000..be81c2f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/models/BookingsView.java @@ -0,0 +1,283 @@ +package com.mgm.mcrm.booking.models; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedEntityGraph; +import jakarta.persistence.NamedEntityGraphs; +import jakarta.persistence.Table; +import jakarta.persistence.Transient; + +import lombok.Data; +import org.hibernate.annotations.Immutable; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.annotation.JsonFormat; + +@Data +@Entity +@Table(name="view_booking") +@Immutable +@NamedEntityGraphs({ + @NamedEntityGraph( + name = "graph.BookingsView.fulldetails", + attributeNodes = { + + } + ) +}) +public class BookingsView implements Serializable { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="revision_of") + private Long revisionOf; + @Column(name="confirmation_no") + private String confirmationNo; + @Column(name="resv_id") + private String resvId; + @Column(name="last_opera_status") + private String lastOperaStatus; + @Column(name="player_id") + private String playerId; + @Column(name="member_title") + private String memberTitle; + @Column(name="member_first_name") + private String memberFirstName; + @Column(name="member_last_name") + private String memberLastName; + @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") + @Column(name="checkin_date") + private Date checkinDate; + @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") + @Column(name="checkout_date") + private Date checkoutDate; + @Column(name="property_id") + private Long propertyId; + @Column(name="room_type_id") + private Long roomTypeId; + @Column(name="dl_profile_id") + private String dlProfileId; + @Column(name="notify_language") + private String notifyLanguage; + @Column(name="payment_amount") + private Double paymentAmount; + @Column(name="opera_total") + private Double operaTotal; + @Column(name="comment") + private String comment; + @Column(name="rate_plan_code") + private String ratePlanCode; + @Column(name="chain_code") + private String chainCode; + @Column(name="hotel_code") + private String hotelCode; + @Column(name="room_type_code") + private String roomTypeCode; + @Column(name="promotion_code") + private String promotionCode; + @Column(name="dl_guarantee_type_id") + private String dlGuaranteeTypeId; + @Column(name="payment_type") + private String paymentType; + @Column(name="market_code") + private String marketCode; + @Column(name="dl_source_id") + private String dlSourceId; + @Column(name="cancelled_by") + private String cancelledBy; + @Column(name="cancelled_at") + private Date cancelledAt; + @Column(name="section_id") + private Long sectionId; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + @Column(name="created_at") + private Date createdAt; + @Column(name="created_by") + private String createdBy; + @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") + @Column(name="updated_at") + private Date updatedAt; + @Column(name="updated_by") + private String updatedBy; + @Column(name="approve_status") + private String approveStatus; + @Column(name="remark") + private String remark; + @Column(name="book_type") + private String bookType; + @Column(name="dl_block_id") + private String dlBlockId; + @Column(name="num_of_night") + private Integer numOfNight; + @Column(name="section_name") + private String sectionName; + @Column(name="booker") + private String booker; + @Column(name="msc_remark") + private String mscRemark; + @Column(name="approval_remark") + private String approvalRemark; + @Column(name="room") + private String room; + @Column(name="sharer") + private String sharer; + @Column(name="feature_code") + private String featureCode; + @Column(name="item_code") + private String itemCode; + @Column(name="group_id") + private String groupId; + @Column(name="property_name") + private String propertyName; + @Column(name="block_id") + private Long blockId; + @Column(name="room_id") + private Long roomId; + @Column(name="property_category") + private String propertyCategory; + @Column(name="bed_type_master_group_id") + private Long bedTypeMasterGroupId; + @Column(name="bed_type_name") + private String bedTypeName; + @Column(name="created_by_name") + private String createdByName; + @Column(name="date_list") + private String dateLists; + @Column(name="room_cn") + private String roomCN; + @Column(name="error_message") + private String errorMessage; + @Column(name="try_time") + private Integer tryTime; + @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") + @Column(name="failed_at") + private Date failedAt; + @Column(name="booking_type_name") + private String bookingTypeName; + @Column(name="room_category") + private String roomCategory; + @Column(name="for_booking") + private Integer roomForBooking; + @Column(name="for_waitlist") + private Integer roomForWaitlist; + @Column(name="segment_id") + private Long segmentId; + @Column(name="requested_co_date") + private Date requestedCoDate; + @Column(name="tier") + private String tier; + @Column(name="gaming_id") + private Long gamingId; + @Column(name="overlap_booking") + private String overlapBooking; + @Column(name="ma_booking") + private String maBooking; + @Column(name="r3_theo_win") + private String r3TheoWin; + @Column(name="r3_tpd") + private String r3Tpd; + @Column(name="r3_actual_win") + private String r3ActualWin; + @Column(name="r6_theo_win") + private String r6TheoWin; + @Column(name="r6_tpd") + private String r6Tpd; + @Column(name="r6_actual_win") + private String r6ActualWin; + @Column(name="r12_theo_win") + private String r12TheoWin; + @Column(name="r12_tpd") + private String r12Tpd; + @Column(name="r12_actual_win") + private String r12ActualWin; + @Column(name="final_segment") + private String finalSegment; + @Column(name="trip_theo_profit") + private String tripTheoProfit; + @Column(name="daily_theo_profit") + private String dailyTheoProfit; + @Column(name="player_type") + private String playerType; + @Column(name="ranking_by_player") + private String rankingByPlayer; + @Column(name="booker_team") + private String bookerTeam; + @Column(name="current_trip_theo_win_amount") + private String currentTripTheoWinAmount; + @Column(name="last_2day_theo_win_amount") + private String last2dayTheoWinAmount; + @Column(name="approved_id") + private Long approvedId; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + @Column(name="approved_at") + private Date approvedAt; + @Column(name="approved_by") + private String approvedBy; + @Column(name="property_email_name") + private String propertyEmailName; + @Column(name="room_email_name") + private String roomEmailName; + @Column(name="eta") + private String eta; + @Column(name="change_checkin_date") + private String changeCheckinDate; + @Column(name="change_checkout_date") + private String changeCheckoutDate; + @Column(name="dl_channel_id") + private String dlChannelId; + @Column(name="dl_account_id") + private String dlAccountId; + @Column(name="dl_reservation_id") + private String dlReservationId; + @Column(name="dl_external_no") + private String dlExternalNo; + @Column(name = "misc_charge") + private String miscCharge; + @Column(name = "booking_type_id") + private Integer bookingTypeId; + @Column(name="opera_profile_id") + private Long operaProfileId; + + @Transient + private String status; + @Transient + private Long pendingRevisionId; + @Transient + private String specialName; + @Transient + private List dateList; + @Transient + private JSONArray sharerList; + @Transient + private String memberTier; + @Transient + private String sharerName; + @Transient + private String expDate; + @Transient + private String profieExpDate; + @Transient + private String roomNo; + @Transient + private boolean isShare; + @Transient + private boolean isQueue; + @Transient + private String dlPropertyId; + @Transient + private String dlRoomTypeId; + @Transient + private List dlSharerIds; + @Transient + private Long dlVersion; + +} diff --git a/src/main/java/com/mgm/mcrm/booking/models/CfgBookingTypes.java b/src/main/java/com/mgm/mcrm/booking/models/CfgBookingTypes.java new file mode 100644 index 0000000..28ff57c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/models/CfgBookingTypes.java @@ -0,0 +1,80 @@ +package com.mgm.mcrm.booking.models; + +import java.io.Serializable; +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; + +@Entity +@Table(name="cfg_booking_types") +public class CfgBookingTypes implements Serializable { + //fields in table + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="name") + private String name; + @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; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/models/GamingData.java b/src/main/java/com/mgm/mcrm/booking/models/GamingData.java new file mode 100644 index 0000000..3200fd7 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/models/GamingData.java @@ -0,0 +1,212 @@ +package com.mgm.mcrm.booking.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; + +@Entity +@Table(name="gaming_data") +public class GamingData { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="book_id") + private Long bookId; + @Column(name="overlap_booking") + private String overlapBooking; + @Column(name="ma_booking") + private String maBooking; + @Column(name="r3_theo_win") + private String r3TheoWin; + @Column(name="r3_tpd") + private String r3Tpd; + @Column(name="r3_actual_win") + private String r3ActualWin; + @Column(name="r6_theo_win") + private String r6TheoWin; + @Column(name="r6_tpd") + private String r6Tpd; + @Column(name="r6_actual_win") + private String r6ActualWin; + @Column(name="r12_theo_win") + private String r12TheoWin; + @Column(name="r12_tpd") + private String r12Tpd; + @Column(name="r12_actual_win") + private String r12ActualWin; + @Column(name="final_segment") + private String finalSegment; + @Column(name="trip_theo_profit") + private String tripTheoProfit; + @Column(name="daily_theo_profit") + private String dailyTheoProfit; + @Column(name="player_type") + private String playerType; + @Column(name="ranking_by_player") + private String rankingByPlayer; + @Column(name="booker_team") + private String bookerTeam; + @Column(name="current_trip_theo_win_amount") + private String currentTripTheoWinAmount; + @Column(name="last_2day_theo_win_amount") + private String last2dayTheoWinAmount; + @Column(name="process_status") + private Integer processStatus; + @Column(name="created_at") + private Date createdAt; + @Column(name="updated_at") + private Date updatedAt; + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public Long getBookId() { + return bookId; + } + public void setBookId(Long bookId) { + this.bookId = bookId; + } + public String getOverlapBooking() { + return overlapBooking; + } + public void setOverlapBooking(String overlapBooking) { + this.overlapBooking = overlapBooking; + } + public String getMaBooking() { + return maBooking; + } + public void setMaBooking(String maBooking) { + this.maBooking = maBooking; + } + public String getR3TheoWin() { + return r3TheoWin; + } + public void setR3TheoWin(String r3TheoWin) { + this.r3TheoWin = r3TheoWin; + } + public String getR3Tpd() { + return r3Tpd; + } + public void setR3Tpd(String r3Tpd) { + this.r3Tpd = r3Tpd; + } + public String getR3ActualWin() { + return r3ActualWin; + } + public void setR3ActualWin(String r3ActualWin) { + this.r3ActualWin = r3ActualWin; + } + public String getR6TheoWin() { + return r6TheoWin; + } + public void setR6TheoWin(String r6TheoWin) { + this.r6TheoWin = r6TheoWin; + } + public String getR6Tpd() { + return r6Tpd; + } + public void setR6Tpd(String r6Tpd) { + this.r6Tpd = r6Tpd; + } + public String getR6ActualWin() { + return r6ActualWin; + } + public void setR6ActualWin(String r6ActualWin) { + this.r6ActualWin = r6ActualWin; + } + public String getR12TheoWin() { + return r12TheoWin; + } + public void setR12TheoWin(String r12TheoWin) { + this.r12TheoWin = r12TheoWin; + } + public String getR12Tpd() { + return r12Tpd; + } + public void setR12Tpd(String r12Tpd) { + this.r12Tpd = r12Tpd; + } + public String getR12ActualWin() { + return r12ActualWin; + } + public void setR12ActualWin(String r12ActualWin) { + this.r12ActualWin = r12ActualWin; + } + public String getFinalSegment() { + return finalSegment; + } + public void setFinalSegment(String finalSegment) { + this.finalSegment = finalSegment; + } + public String getTripTheoProfit() { + return tripTheoProfit; + } + public void setTripTheoProfit(String tripTheoProfit) { + this.tripTheoProfit = tripTheoProfit; + } + public String getDailyTheoProfit() { + return dailyTheoProfit; + } + public void setDailyTheoProfit(String dailyTheoProfit) { + this.dailyTheoProfit = dailyTheoProfit; + } + public String getPlayerType() { + return playerType; + } + public void setPlayerType(String playerType) { + this.playerType = playerType; + } + public String getRankingByPlayer() { + return rankingByPlayer; + } + public void setRankingByPlayer(String rankingByPlayer) { + this.rankingByPlayer = rankingByPlayer; + } + public String getBookerTeam() { + return bookerTeam; + } + public void setBookerTeam(String bookerTeam) { + this.bookerTeam = bookerTeam; + } + public String getCurrentTripTheoWinAmount() { + return currentTripTheoWinAmount; + } + public void setCurrentTripTheoWinAmount(String currentTripTheoWinAmount) { + this.currentTripTheoWinAmount = currentTripTheoWinAmount; + } + public String getLast2dayTheoWinAmount() { + return last2dayTheoWinAmount; + } + public void setLast2dayTheoWinAmount(String last2dayTheoWinAmount) { + this.last2dayTheoWinAmount = last2dayTheoWinAmount; + } + public Date getCreatedAt() { + return createdAt; + } + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + public Date getUpdatedAt() { + return updatedAt; + } + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + public Integer getProcessStatus() { + return processStatus; + } + public void setProcessStatus(Integer processStatus) { + this.processStatus = processStatus; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/models/NonMGMBookings.java b/src/main/java/com/mgm/mcrm/booking/models/NonMGMBookings.java new file mode 100644 index 0000000..2d7cdb8 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/models/NonMGMBookings.java @@ -0,0 +1,155 @@ +package com.mgm.mcrm.booking.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; + +@Entity +@Table(name="non_mgm_bookings") +public class NonMGMBookings { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="player_id") + private String playerId; + @Column(name="confirmation_no") + private String confirmationNo; + @Column(name="property") + private String property; + @Column(name="property_id") + private Long propertyId; + @Column(name="room_id") + private Long roomId; + @Column(name="status_name") + private String statusName; + @Column(name="room_type_status") + private String roomTypeStatus; + @Column(name="check_in_date_str") + private String checkInDateStr; + @Column(name="check_in_date") + private Date checkInDate; + @Column(name="check_out_date_str") + private String checkOutDateStr; + @Column(name="check_out_date") + private Date checkOutDate; + @Column(name="created_on_str") + private String createdOnStr; + @Column(name="created_on") + private Date createdOn; + @Column(name="created_by") + private String createdBy; + @Column(name="rec_created_at") + private Date recCreatedAt; + @Column(name="rec_updated_at") + private Date recUpdatedAt; + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public String getPlayerId() { + return playerId; + } + public void setPlayerId(String playerId) { + this.playerId = playerId; + } + public String getConfirmationNo() { + return confirmationNo; + } + public void setConfirmationNo(String confirmationNo) { + this.confirmationNo = confirmationNo; + } + public String getProperty() { + return property; + } + public void setProperty(String property) { + this.property = property; + } + public String getCheckInDateStr() { + return checkInDateStr; + } + public void setCheckInDateStr(String checkInDateStr) { + this.checkInDateStr = checkInDateStr; + } + public Date getCheckInDate() { + return checkInDate; + } + public void setCheckInDate(Date checkInDate) { + this.checkInDate = checkInDate; + } + public String getCheckOutDateStr() { + return checkOutDateStr; + } + public void setCheckOutDateStr(String checkOutDateStr) { + this.checkOutDateStr = checkOutDateStr; + } + public Date getCheckOutDate() { + return checkOutDate; + } + public void setCheckOutDate(Date checkOutDate) { + this.checkOutDate = checkOutDate; + } + public String getCreatedOnStr() { + return createdOnStr; + } + public void setCreatedOnStr(String createdOnStr) { + this.createdOnStr = createdOnStr; + } + public Date getCreatedOn() { + return createdOn; + } + public void setCreatedOn(Date createdOn) { + this.createdOn = createdOn; + } + public String getCreatedBy() { + return createdBy; + } + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + public Date getRecCreatedAt() { + return recCreatedAt; + } + public void setRecCreatedAt(Date recCreatedAt) { + this.recCreatedAt = recCreatedAt; + } + public Date getRecUpdatedAt() { + return recUpdatedAt; + } + public void setRecUpdatedAt(Date recUpdatedAt) { + this.recUpdatedAt = recUpdatedAt; + } + public String getRoomTypeStatus() { + return roomTypeStatus; + } + public void setRoomTypeStatus(String roomTypeStatus) { + this.roomTypeStatus = roomTypeStatus; + } + public Long getRoomId() { + return roomId; + } + public void setRoomId(Long roomId) { + this.roomId = roomId; + } + public String getStatusName() { + return statusName; + } + public void setStatusName(String statusName) { + this.statusName = statusName; + } + public Long getPropertyId() { + return propertyId; + } + public void setPropertyId(Long propertyId) { + this.propertyId = propertyId; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/models/OWSTransactions.java b/src/main/java/com/mgm/mcrm/booking/models/OWSTransactions.java new file mode 100644 index 0000000..9f0343d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/models/OWSTransactions.java @@ -0,0 +1,63 @@ +package com.mgm.mcrm.booking.models; + +import java.io.Serializable; +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 com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +@Data +@Entity +@Table(name = "ows_transactions") +public class OWSTransactions implements Serializable { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + @Column(name = "service") + private String service; + + @Column(name = "action") + private String action; + + @Column(name = "success") + private int success; + + @Column(name = "execute_time_ms") + private int executeTimeMs; + + @Column(name = "user_id") + private int userId; + + @Column(name = "request") + private String request; + + @Column(name = "response") + private String response; + + @Column(name = "error_code") + private String errorCode; + + @Column(name = "error_message") + private String errorMessage; + + @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") + @Column(name = "created_at") + private Date createdAt; + + @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8") + @Column(name = "updated_at") + private Date updatedAt; + + @Column(name = "url_action") + private String urlAction; +} diff --git a/src/main/java/com/mgm/mcrm/booking/models/OperaComment.java b/src/main/java/com/mgm/mcrm/booking/models/OperaComment.java new file mode 100644 index 0000000..0ef009f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/models/OperaComment.java @@ -0,0 +1,29 @@ +package com.mgm.mcrm.booking.models; + +import jakarta.persistence.*; +import lombok.Data; + +@Entity +@NamedStoredProcedureQueries({ + @NamedStoredProcedureQuery( + name = "GetOracleComment_OpenQuery", + procedureName = "GetOracleComment_OpenQuery", + resultClasses = OperaComment.class, + parameters = { + @StoredProcedureParameter(mode = ParameterMode.IN, name = "commentId", type = Integer.class), + @StoredProcedureParameter(mode = ParameterMode.IN, name = "resvNameId", type = Integer.class), + } + ) +}) +@Data +public class OperaComment { + + @Id + @Column(name="RESV_COMMENT_ID") + private String resvCommentId; + @Column(name="COMMENT_TYPE") + private String commentType; + @Column(name="COMMENTS") + private String comments; + +} diff --git a/src/main/java/com/mgm/mcrm/booking/models/OperaDBBooking.java b/src/main/java/com/mgm/mcrm/booking/models/OperaDBBooking.java new file mode 100644 index 0000000..59bcfb5 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/models/OperaDBBooking.java @@ -0,0 +1,246 @@ +package com.mgm.mcrm.booking.models; + + +import java.sql.Date; + +import jakarta.persistence.*; + +@Entity +@NamedStoredProcedureQueries({ + @NamedStoredProcedureQuery( + name = "getBookingsByConfirmationNo", + procedureName = "GetBookingsByConfirmationNo", + resultClasses = OperaDBBooking.class, + parameters = { + @StoredProcedureParameter(mode = ParameterMode.IN,name = "confirmation_no",type = String.class) + } + ), + @NamedStoredProcedureQuery( + name = "getBookingsByNameID", + procedureName = "GetBookingsByNameID", + resultClasses = OperaDBBooking.class, + parameters = { + @StoredProcedureParameter(mode = ParameterMode.IN,name = "name_id",type = String.class), + @StoredProcedureParameter(mode = ParameterMode.IN,name = "block_code",type = String.class), + @StoredProcedureParameter(mode = ParameterMode.IN,name = "enddate",type = Date.class) + } + ), + @NamedStoredProcedureQuery( + name = "getOperaNameIDByPlayerID", + procedureName = "GetOperaNameIDByPlayerID", + parameters = { + @StoredProcedureParameter(mode = ParameterMode.IN,name = "player_id",type = String.class), + } + ), + @NamedStoredProcedureQuery( + name = "getBookingsByRoomNo", + procedureName = "GetBookingsByRoomNo", + resultClasses = OperaDBBooking.class, + parameters = { + @StoredProcedureParameter(mode = ParameterMode.IN,name = "room_no",type = String.class) + } + ), + @NamedStoredProcedureQuery( + name = "checkDBConnection", + procedureName = "CheckDBConnection" + ) +}) + +public class OperaDBBooking { + + @Id + @Column(name="Confirmation_No") + private String confirmationNo; + @Column(name="RESORT") + private String resort; + @Column(name="Room_Type") + private String roomType; + @Column(name="Room_Type_Desc") + private String roomTypeDesc; + @Column(name="Arrival_date") + private String arrivalDate; + @Column(name="Arrival_Time") + private String arrivalTime; + @Column(name="Departture_Date") + private String departureDate; + @Column(name="Departure_Time") + private String departureTime; + @Column(name="Resv_Status") + private String resvStatus; + @Column(name="Block_Code") + private String blockCode; + @Column(name="Current_Balance") + private String currentBalance; + @Column(name="Opera_Profile_ID") + private String operaProfileId; + @Column(name="Resv_Name_ID") + private String resvNameId; + @Column(name="Rate_Code") + private String rateCode; + @Column(name="Adults") + private String adults; + @Column(name="Children") + private String children; + @Column(name="Market_Segment") + private String marketSegment; + @Column(name="Source_Code") + private String sourceCode; + @Column(name="Source_Name") + private String sourceName; + @Column(name="Booker") + private String booker; + @Column(name="EXP_Date") + private String expDate; + @Column(name="Profile_EXP_Date") + private String profileExpDate; + @Column(name="Room_No") + private String roomNo; + @Column(name="Is_Queue") + private String isQueue; + + public String getConfirmationNo() { + return confirmationNo; + } + public void setConfirmationNo(String confirmationNo) { + this.confirmationNo = confirmationNo; + } + public String getRoomType() { + return roomType; + } + public void setRoomType(String roomType) { + this.roomType = roomType; + } + public String getRoomTypeDesc() { + return roomTypeDesc; + } + public void setRoomTypeDesc(String roomTypeDesc) { + this.roomTypeDesc = roomTypeDesc; + } + public String getArrivalDate() { + return arrivalDate; + } + public void setArrivalDate(String arrivalDate) { + this.arrivalDate = arrivalDate; + } + public String getArrivalTime() { + return arrivalTime; + } + public void setArrivalTime(String arrivalTime) { + this.arrivalTime = arrivalTime; + } + public String getDepartureDate() { + return departureDate; + } + public void setDepartureDate(String departureDate) { + this.departureDate = departureDate; + } + public String getDepartureTime() { + return departureTime; + } + public void setDepartureTime(String departureTime) { + this.departureTime = departureTime; + } + public String getResvStatus() { + return resvStatus; + } + public void setResvStatus(String resvStatus) { + this.resvStatus = resvStatus; + } + public String getBlockCode() { + return blockCode; + } + public void setBlockCode(String blockCode) { + this.blockCode = blockCode; + } + public String getCurrentBalance() { + return currentBalance; + } + public void setCurrentBalance(String currentBalance) { + this.currentBalance = currentBalance; + } + public String getOperaProfileId() { + return operaProfileId; + } + public void setOperaProfileId(String operaProfileId) { + this.operaProfileId = operaProfileId; + } + public String getResvNameId() { + return resvNameId; + } + public void setResvNameId(String resvNameId) { + this.resvNameId = resvNameId; + } + public String getRateCode() { + return rateCode; + } + public void setRateCode(String rateCode) { + this.rateCode = rateCode; + } + public String getAdults() { + return adults; + } + public void setAdults(String adults) { + this.adults = adults; + } + public String getChildren() { + return children; + } + public void setChildren(String children) { + this.children = children; + } + public String getMarketSegment() { + return marketSegment; + } + public void setMarketSegment(String marketSegment) { + this.marketSegment = marketSegment; + } + public String getSourceCode() { + return sourceCode; + } + public void setSourceCode(String sourceCode) { + this.sourceCode = sourceCode; + } + public String getSourceName() { + return sourceName; + } + public void setSourceName(String sourceName) { + this.sourceName = sourceName; + } + public String getResort() { + return resort; + } + public void setResort(String resort) { + this.resort = resort; + } + public String getBooker() { + return booker; + } + public void setBooker(String booker) { + this.booker = booker; + } + public String getExpDate() { + return expDate; + } + public void setExpDate(String expDate) { + this.expDate = expDate; + } + public String getProfileExpDate() { + return profileExpDate; + } + public void setProfileExpDate(String profileExpDate) { + this.profileExpDate = profileExpDate; + } + public String getRoomNo() { + return roomNo; + } + public void setRoomNo(String roomNo) { + this.roomNo = roomNo; + } + public String getIsQueue() { + return isQueue; + } + public void setIsQueue(String isQueue) { + this.isQueue = isQueue; + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/models/OperaDBRate.java b/src/main/java/com/mgm/mcrm/booking/models/OperaDBRate.java new file mode 100644 index 0000000..d15161c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/models/OperaDBRate.java @@ -0,0 +1,124 @@ +package com.mgm.mcrm.booking.models; + + +import jakarta.persistence.*; + +@Entity +@NamedStoredProcedureQueries({ + @NamedStoredProcedureQuery( + name = "getBookingsRate", + procedureName = "GetBookingsRate", + resultClasses = OperaDBRate.class, + parameters = { + @StoredProcedureParameter(mode = ParameterMode.IN,name = "rate_code",type = String.class), + @StoredProcedureParameter(mode = ParameterMode.IN,name = "room_type",type = String.class), + @StoredProcedureParameter(mode = ParameterMode.IN,name = "start_date",type = String.class), + @StoredProcedureParameter(mode = ParameterMode.IN,name = "end_date",type = String.class) + } + ) + +}) + +public class OperaDBRate { + @Id + @Column(name="ID") + private String id; + @Column(name="RESORT") + private String resort; + @Column(name="BEGIN_DATE") + private String beginDate; + @Column(name="END_DATE") + private String endDate; + @Column(name="Day1") + private String day1; + @Column(name="Day2") + private String day2; + @Column(name="Day3") + private String day3; + @Column(name="Day4") + private String day4; + @Column(name="Day5") + private String day5; + @Column(name="Day6") + private String day6; + @Column(name="Day7") + private String day7; + @Column(name="Amount1") + private String amount1; + + + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + public String getResort() { + return resort; + } + public void setResort(String resort) { + this.resort = resort; + } + public String getBeginDate() { + return beginDate; + } + public void setBeginDate(String beginDate) { + this.beginDate = beginDate; + } + public String getEndDate() { + return endDate; + } + public void setEndDate(String endDate) { + this.endDate = endDate; + } + public String getDay1() { + return day1; + } + public void setDay1(String day1) { + this.day1 = day1; + } + public String getDay2() { + return day2; + } + public void setDay2(String day2) { + this.day2 = day2; + } + public String getDay3() { + return day3; + } + public void setDay3(String day3) { + this.day3 = day3; + } + public String getDay4() { + return day4; + } + public void setDay4(String day4) { + this.day4 = day4; + } + public String getDay5() { + return day5; + } + public void setDay5(String day5) { + this.day5 = day5; + } + public String getDay6() { + return day6; + } + public void setDay6(String day6) { + this.day6 = day6; + } + public String getDay7() { + return day7; + } + public void setDay7(String day7) { + this.day7 = day7; + } + public String getAmount1() { + return amount1; + } + public void setAmount1(String amount1) { + this.amount1 = amount1; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/booking/repositories/BookingDao.java b/src/main/java/com/mgm/mcrm/booking/repositories/BookingDao.java new file mode 100644 index 0000000..4593949 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/repositories/BookingDao.java @@ -0,0 +1,96 @@ +package com.mgm.mcrm.booking.repositories; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +import com.mgm.mcrm.booking.models.Bookings; + +@Repository +public interface BookingDao extends JpaRepository { + + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + ArrayList findByIdIn(ArrayList ids); + + @Query(value="select Top(1) * from bookings where try_time between 0 and 4 and approve_status in('F') and process_status!=1",nativeQuery=true) + List getFailedBooking(); + + //FOR DEV add reserverd and due in status + @Query(value="select * from bookings where (checkout_date=?1) and player_id=?2 and created_by=?3 and property_id=?4 and room_id=?5 and" + + "(last_opera_status='CHECKED_IN' or last_opera_status='DUE_OUT' or last_opera_status='RESERVED' or last_opera_status='DUE_IN')",nativeQuery=true) + List getExtendBooking(Date checkoutDate,String playerId,String userId,String propertyId,String roomId); + + //FOR DEV add reserverd and due in status + @Query(value="select * from bookings where (checkout_date=?1 or checkin_date=?6) and player_id=?2 and created_by=?3 and property_id=?4 and room_id=?5 and" + + "(last_opera_status='CHECKED_IN' or last_opera_status='DUE_OUT' or last_opera_status='RESERVED' or last_opera_status='DUE_IN')",nativeQuery=true) + List getExtendBooking2(Date checkoutDate,String playerId,String userId,String propertyId,String roomId,Date checkinDate); + + + @Query(value="select * from bookings where checkin_date<=?2 and checkout_date>=?1 and player_id=?3 and created_by=?4 and" + + "(approve_status='W')",nativeQuery=true) + List getWaitlistBooking(Date checkinDate,Date checkoutDate,String playerId,String userId); + + @Query(value="select count(*) from bookings where checkin_date=?1 and checkout_date=?2 and failed_room_type like %?3% and error_message like '%No available room%' ",nativeQuery=true) + Integer checkRoomTypeFailedBooking(Date checkinDate,Date checkoutDate,String roomTypeCode); + + @Query(value="select Top(1) * from bookings where approve_status='W' and checkin_date < CAST(GETDATE() AS DATE)",nativeQuery=true) + List getExpiryWaitlistBooking(); + + @Transactional + @Modifying + @Query(value = " update bookings set process_status=?2 where id=?1",nativeQuery=true) + int updateProcessStatus(long id,Integer processStatus); + + @Transactional + @Modifying + @Query(value = "update bookings set approve_status='WE' where id=?1",nativeQuery=true) + int expiryWaitlistBooking(long id); + + @Transactional + @Modifying + @Query(value = " delete from bookings where id>?1 and confirmation_no=?2 ",nativeQuery=true) + int deleteDuplicateBooking(long id,String confirmation_no); + + @Transactional + @Modifying + @Query(value = " update bookings set approve_status=?1 where id in (?2)",nativeQuery=true) + int updateBatchStatus(String status,String[] ids); + + @Transactional + @Modifying + @Query(value = " update bookings set approved_id=?1,approved_by=?2,approved_at=?3 where id in (?4)",nativeQuery=true) + int updateBatchApprover(Long id,String name,Date date,String[] ids); + + @Query(value="select Top(20) b.* from bookings b left join gaming_data g on b.id=g.book_id where b.approve_status='W' and (g.updated_at is null)",nativeQuery=true) + List getPendingWaitlistBooking(); + + @Query(value="select count(*) from bookings where property_id=?1 and room_id=?2 and segment_id=?3 " + + "and((checkin_date<=?4 and checkout_date>?4) or (checkout_date<=?4 and requested_co_date>?4)) and other_room_status_id in (?5) and approve_status in('N','PN','C')",nativeQuery=true) + int getOtherPickupBooking(Long propertyId,long roomId,Long segmentId,Date date,Long[] roomStatusId); + + @Query(value="select count(*) from bookings where property_id=?1 and room_id=?2 and block_id=?3 " + + "and((checkin_date<=?4 and checkout_date>?4))and approve_status in('N') and section_id is not null",nativeQuery=true) + int getPickupBooking(Long propertyId,Long roomId,Long blockId,Date date); + + @Query(value="select * from bookings where confirmation_no =?1 and approve_status not like '%W%' and approve_status != 'C' and property_id = ?2",nativeQuery=true) + Bookings getByConfNoForETA(String confNo,Long propertyId); + + @Query(value = "select * from bookings where confirmation_no =?1", nativeQuery = true) + Bookings getByConfNo(String confNo); + + @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); + +} diff --git a/src/main/java/com/mgm/mcrm/booking/repositories/BookingTypeDao.java b/src/main/java/com/mgm/mcrm/booking/repositories/BookingTypeDao.java new file mode 100644 index 0000000..b24c8a6 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/repositories/BookingTypeDao.java @@ -0,0 +1,22 @@ +package com.mgm.mcrm.booking.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import com.mgm.mcrm.booking.models.CfgBookingTypes; + + + +public interface BookingTypeDao extends JpaRepository { + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + + CfgBookingTypes findCfgBookingTypesById(Long id); +} diff --git a/src/main/java/com/mgm/mcrm/booking/repositories/BookingViewDao.java b/src/main/java/com/mgm/mcrm/booking/repositories/BookingViewDao.java new file mode 100644 index 0000000..1052d59 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/repositories/BookingViewDao.java @@ -0,0 +1,136 @@ +package com.mgm.mcrm.booking.repositories; + +import java.util.Date; +import java.util.List; + +import com.mgm.mcrm.booking.models.BookingsView; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.EntityGraph; +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; + + + +public interface BookingViewDao extends JpaRepository { + BookingsView findById(long id); + List findByConfirmationNoIn(List confirmationNo); + BookingsView findByIdAndPlayerIdContainingIgnoreCase(long id, String playerId); + List findByDlReservationIdIn(List dlReservationId); + List findByDlExternalNoIn(List dlExternalNo); + List findByConfirmationNo(String confirmationNo); + List findByPlayerId(String playerId); + + @EntityGraph(value = "graph.BookingsView.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + Page findAll(Specification spec, Pageable pageable); + + @EntityGraph(value = "graph.BookingsView.fulldetails",type = EntityGraph.EntityGraphType.LOAD) + List findAll(Specification spec, Sort sort); + + @Query(value="select * from view_booking where player_id=:player_id and" + + " checkin_date >=:checkin_date and checkout_date<=:checkout_date and created_at >=:date and" + + " approve_status in('PN','F') and segment_id is null",nativeQuery=true) + List findRecordSearchPending(@Param("player_id") String payerId,@Param("checkin_date") + String checkinDate,@Param("checkout_date") String checkoutDate,@Param("date") String date); + +// @Query(value="select * from view_booking where player_id=:player_id and" +// + " checkin_date >=:checkin_date and checkout_date<=:checkout_date and" +// + " approve_status in('N','C') and (last_opera_status not in('CHECKED_OUT','NO_SHOW') or last_opera_status is null) " +// + "and revision_of is null and segment_id is null",nativeQuery=true) +// List findRecordSearchMock( +// @Param("player_id") String payerId, +// @Param("checkin_date") String checkinDate, +// @Param("checkout_date") String checkoutDate +// ); + @Query(value = "select * from view_booking where player_id = :player_id " + + "and checkin_date >= :checkin_date " + + "and checkout_date <= :checkout_date " + + "and checkout_date >= CAST(GETDATE() AS DATE) " + + "and approve_status in ('N','C') " + + "and (last_opera_status not in ('CHECKED_OUT','NO_SHOW') or last_opera_status is null) " + + "and revision_of is null " + + "and segment_id is null", + nativeQuery = true) + List findRecordSearchMock( + @Param("player_id") String playerId, + @Param("checkin_date") String checkinDate, + @Param("checkout_date") String checkoutDate + ); + + @Query(value="select * from view_booking where confirmation_no=?1 and approve_status not in('WC','WF','WE') and player_id is not null",nativeQuery=true) + List findBookingByConfirmationNo(String conf); + + @Query(value="select * from view_booking where player_id=:player_id and" + + " checkin_date >=:checkin_date and checkout_date<=:checkout_date and created_at >=:date and" + + " approve_status in('AP') and segment_id is null",nativeQuery=true) + List findRecordSearchPendingApproval(@Param("player_id") String payerId,@Param("checkin_date") + String checkinDate,@Param("checkout_date") String checkoutDate,@Param("date") String date); + + @Query(value="select * from view_booking where id=?1",nativeQuery=true) + List findBookingById(long id); + + @Query(value="select * from view_booking where group_id=?1 and approve_status not in('WC','WF','WE')",nativeQuery=true) + List findBookingsByGroupId(String groupId); + + @Transactional + @Modifying + @Query(value="update bookings set last_opera_status='DUE_IN' where cast(checkin_date as date)=cast(getdate() as date) " + + " and CAST(GETDATE() AS TIME) <'12:00:00'" + + " and cast(checkout_date as date)>cast(getdate() as date) " + + " and (last_opera_status is null or last_opera_status='RESERVED') and approve_status='N'",nativeQuery=true) + void changeDueIn(); + + @Transactional + @Modifying + @Query(value="update bookings set last_opera_status='CHECKED_IN' where cast(checkin_date as date)=cast(getdate() as date) " + + " and CAST(GETDATE() AS TIME) >= '12:00:00'" + + " and cast(checkout_date as date)>cast(getdate() as date) " + + " and (last_opera_status is null or last_opera_status='DUE_IN' or last_opera_status='RESERVED') and approve_status='N'",nativeQuery=true) + void changeCheckedIn(); + + @Transactional + @Modifying + @Query(value="update bookings set last_opera_status='DUE_OUT' where cast(checkout_date as date)=cast(getdate() as date)" + + " and (last_opera_status is null or last_opera_status='CHECKED_IN') and approve_status='N'",nativeQuery=true) + void changeDueOut(); + + @Transactional + @Modifying + @Query(value="update bookings set last_opera_status='CHECKED_OUT' where cast(checkout_date as date) findWaitlistBooking(); + + @Query(value="select * from view_booking where checkout_date<=?1 and player_id=?2 and (approve_status in('N','PN') or (confirmation_no is not null and approve_status in('F','FC')))",nativeQuery=true) + List getCalendarBooking(Date checkoutDate,String playerId); + + @Query(value="select * from view_booking where player_id=?1 and cast(checkout_date as date)>=cast(getdate() as date) and" + + " approve_status in('W','WA')",nativeQuery=true) + List findShowWaitlisBooking(String playerId); + + @Query(value="select * from view_booking where player_id=?1 and" + + " approve_status in('N','PN','AP') and segment_id is not null and property_category='OTHER' and cast(checkout_date as date) >= cast(?2 as date) " + + " and cast(checkin_date as date) <= cast(?3 as date)",nativeQuery=true) + List findNonMGMBooking(String playerId,Date startDate,Date endDate); + + @Query(value="select * from view_booking where id in (?1)",nativeQuery=true) + List findBookingByIds(String[] ids); + + @Query(value="select * from view_booking where player_id = ?1 and approve_status = 'AP' and approver_id like concat('%', ?2, '%')",nativeQuery=true) + List getPendingApprovalBookingList(String playerId, String approverId); + + BookingsView findByid(Long id); +} diff --git a/src/main/java/com/mgm/mcrm/booking/repositories/GamingDataDao.java b/src/main/java/com/mgm/mcrm/booking/repositories/GamingDataDao.java new file mode 100644 index 0000000..751030c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/repositories/GamingDataDao.java @@ -0,0 +1,15 @@ +package com.mgm.mcrm.booking.repositories; + +import java.util.List; + +import com.mgm.mcrm.booking.models.GamingData; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + + +public interface GamingDataDao extends JpaRepository { + List findByBookId(Long bookId); + +} diff --git a/src/main/java/com/mgm/mcrm/booking/repositories/NonMGMBookingDao.java b/src/main/java/com/mgm/mcrm/booking/repositories/NonMGMBookingDao.java new file mode 100644 index 0000000..4829c4d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/repositories/NonMGMBookingDao.java @@ -0,0 +1,23 @@ +package com.mgm.mcrm.booking.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; + +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.booking.models.NonMGMBookings; + +public interface NonMGMBookingDao extends JpaRepository{ + + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + + List findAllByPlayerId(String playerId); + List findAllByPlayerIdAndConfirmationNo(String playerId, String confirmationNo); + +} diff --git a/src/main/java/com/mgm/mcrm/booking/repositories/NonMGMStatusMappingDao.java b/src/main/java/com/mgm/mcrm/booking/repositories/NonMGMStatusMappingDao.java new file mode 100644 index 0000000..8fbdb65 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/repositories/NonMGMStatusMappingDao.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.booking.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; + +import com.mgm.mcrm.basesetting.daylight.models.CfgNonMGMStatusMapping; + +public interface NonMGMStatusMappingDao extends JpaRepository { + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + + List findAllByStatusCodeAndPropertyId(String statusCode,Long propertyId); +} diff --git a/src/main/java/com/mgm/mcrm/booking/repositories/OWSTransactionsRepository.java b/src/main/java/com/mgm/mcrm/booking/repositories/OWSTransactionsRepository.java new file mode 100644 index 0000000..74e41b2 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/repositories/OWSTransactionsRepository.java @@ -0,0 +1,14 @@ +package com.mgm.mcrm.booking.repositories; + +import com.mgm.mcrm.booking.models.OWSTransactions; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + + + + +public interface OWSTransactionsRepository extends JpaRepository { + + @Query(value="select top 1 * from ows_transactions with (nolock) order by id desc",nativeQuery=true) + OWSTransactions findMaxId(); +} diff --git a/src/main/java/com/mgm/mcrm/booking/repositories/OtherAppChannelDao.java b/src/main/java/com/mgm/mcrm/booking/repositories/OtherAppChannelDao.java new file mode 100644 index 0000000..10ad431 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/repositories/OtherAppChannelDao.java @@ -0,0 +1,14 @@ +package com.mgm.mcrm.booking.repositories; + +import com.mgm.mcrm.allotment.models.CfgOtherAppChannel; +import com.mgm.mcrm.allotment.models.CfgOtherAppChannelKey; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + + + +public interface OtherAppChannelDao extends JpaRepository { + +} diff --git a/src/main/java/com/mgm/mcrm/booking/repositories/OtherFollowUpStatusDao.java b/src/main/java/com/mgm/mcrm/booking/repositories/OtherFollowUpStatusDao.java new file mode 100644 index 0000000..c07210f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/repositories/OtherFollowUpStatusDao.java @@ -0,0 +1,15 @@ +package com.mgm.mcrm.booking.repositories; + +import java.util.List; + +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; + +import com.mgm.mcrm.basesetting.daylight.models.CfgOtherFollowUpStatus; + + +public interface OtherFollowUpStatusDao extends JpaRepository { + CfgOtherFollowUpStatus findById(long id); + List findAll(Specification spec,Sort sort); +} diff --git a/src/main/java/com/mgm/mcrm/booking/services/BookingService.java b/src/main/java/com/mgm/mcrm/booking/services/BookingService.java new file mode 100644 index 0000000..cbd7d2d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/services/BookingService.java @@ -0,0 +1,6111 @@ +package com.mgm.mcrm.booking.services; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.gson.Gson; +import com.mgm.mcrm.allotment.models.CfgAppChannel; +import com.mgm.mcrm.allotment.models.CfgRoomCriterias; +import com.mgm.mcrm.allotment.repositories.AppChannelDao; +import com.mgm.mcrm.allotment.repositories.RoomCriteriaDao; +import com.mgm.mcrm.approval.dtos.GetApproverRequest; +import com.mgm.mcrm.approval.service.ApprovalService; +import com.mgm.mcrm.appsetting.models.CfgSettings; +import com.mgm.mcrm.appsetting.services.SettingService; +import com.mgm.mcrm.appsetting.services.SysSettingService; +import com.mgm.mcrm.authorization.services.MgmUserService; +import com.mgm.mcrm.authorization.services.SysGroupPermissionService; +import com.mgm.mcrm.basesetting.agebucket.models.SysAgebucket; +import com.mgm.mcrm.basesetting.agebucket.services.AgebucketService; +import com.mgm.mcrm.basesetting.daylight.dtos.ProfileMemberships; +import com.mgm.mcrm.basesetting.daylight.dtos.response.CancelReasonResponse; +import com.mgm.mcrm.basesetting.daylight.dtos.response.ProfileDetailResponse; +import com.mgm.mcrm.basesetting.daylight.dtos.response.ReservationNoteResponse; +import com.mgm.mcrm.basesetting.daylight.models.*; +import com.mgm.mcrm.basesetting.daylight.repositories.*; +import com.mgm.mcrm.basesetting.daylight.services.DaylightService; +import com.mgm.mcrm.basesetting.property.models.CfgProperties; +import com.mgm.mcrm.basesetting.property.repositories.PropertyDao; +import com.mgm.mcrm.basesetting.property.services.PropertyCache; +import com.mgm.mcrm.basesetting.room.models.*; +import com.mgm.mcrm.basesetting.room.repositories.*; +import com.mgm.mcrm.booking.dtos.*; +import com.mgm.mcrm.booking.dtos.daylight.requests.createReservation.*; +import com.mgm.mcrm.booking.dtos.daylight.responses.DistributionChannelResponse; +import com.mgm.mcrm.booking.dtos.daylight.responses.GuaranteeTypeResponse; +import com.mgm.mcrm.booking.dtos.opera.*; +import com.mgm.mcrm.booking.dtos.search.BookingQueryRequest; +import com.mgm.mcrm.booking.enums.ProfileTierEnums; +import com.mgm.mcrm.booking.mappers.BookingMapper; +import com.mgm.mcrm.booking.models.*; +import com.mgm.mcrm.booking.repositories.BookingDao; +import com.mgm.mcrm.booking.repositories.BookingTypeDao; +import com.mgm.mcrm.booking.repositories.BookingViewDao; +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.constants.SysConstants; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.common.dtos.DataTableResult; +import com.mgm.mcrm.common.dtos.EumnApprovalStatus; +import com.mgm.mcrm.common.dtos.mgm_api.*; +import com.mgm.mcrm.common.jms.BookingControlMsgSender; +import com.mgm.mcrm.common.utils.DaoUtil; +import com.mgm.mcrm.common.utils.DateTimeUtil; +import com.mgm.mcrm.common.utils.LogUtil; +import com.mgm.mcrm.common.utils.SendEmail; +import com.mgm.mcrm.logging.services.SysLogBookingService; +import com.mgm.mcrm.notification.models.Email; +import com.mgm.mcrm.notification.repositories.EmailDao; +import com.mgm.mcrm.player.dtos.request.TodoChangeDateRequest; +import com.mgm.mcrm.player.dtos.response.DaylightReservationResponse; +import com.mgm.mcrm.player.services.PlayerService; +import jakarta.annotation.Resource; +import jakarta.persistence.Transient; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Root; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class BookingService { + + @Autowired + private BookingControlMsgSender ctrlMsgSender; + @Resource + private BookingDao bookingDao; + @Resource + private PropertyDao propertyDao; + @Resource + private BedTypeMappingDao bedTypeMappingDao; + @Resource + private RoomDao roomDao; + @Resource + private RoomTypeDao roomTypeDao; + @Resource + private TierDao tierDao; + @Resource + private ItemInventoryDao itemDao; + @Resource + private BookingViewDao bookingViewDao; + @Resource + private RoomFeatureDao roomFeatureDao; + @Resource + private SysSettingService sysSettingService; + @Resource + private DaylightViewDao daylightViewDao; + @Resource + private OperaDBBookingService operaDBService; + @Resource + private AppChannelDao appChannelDao; + @Resource + private RoomCriteriaDao criteriaDao; + @Resource + private RoomRoomTypeDao roomRoomTypeDao; + @Resource + private ExceptionDaylightViewDao exceptionDaylightViewDao; + @Resource + OperaService operaService; + @Resource + private BlockCodeDao blockCodeDao; + @Resource + private EmailDao emailDao; + @Resource + private ApprovalService approvalService; + @Resource + private MarketCodeDao marketCodeDao; + @Resource + private RateCodeDao rateCodeDao; + @Resource + private SysLogBookingService sysLogBookingService; + @Resource + private NonMGMBookingService otherBookingService; + @Resource + private SettingService settingService; + @Resource + private PlayerService playerService; + @Resource + private MgmUserService mgmUserService; + @Resource + private OperaViewDao operaViewDao; + @Resource + private SourceCodeDao sourceCodeDao; + @Resource + private DaylightService dlService; + @Resource + private AgebucketService agebucketService; + @Resource + private ExceptionOperaViewDao exceptionOperaViewDao; + @Resource + private PropertyCache propertyCache; + @Resource + private SysGroupPermissionService sysGroupPermissionService; + @Resource + private BookingTypeDao bookingTypeDao; + + @Autowired + private BookingMapper bookingMapper; + + @Value("${mcrm.daylight-system-id}") + private String daylightSystemId; + + @Resource + private OperaDBBookingService operaDBBookingService; + + public BaseApiResponse> createBooking(BookingDto param, HttpServletRequest request, UserInfoApiRecord userInfo, String category) throws Exception { + + if ("DAYLIGHT".equals(category)) { + return createDaylightBooking(param, request, userInfo); + } + + if ("OPERA".equals(category)) { + return createOperaBooking(param, request, userInfo); + } + + if ("OTHER".equals(category)) { + return createOtherBooking(param, request, userInfo); + } + + BaseApiResponse> response = new BaseApiResponse<>(); + + response.setSuccess(false); + response.setMessage("Create booking fail, unknown category: " + category); + log.warn("Create booking fail, unknown category: {}", category); + + return response; + } + + private BaseApiResponse> createOtherBooking( + BookingDto param, + HttpServletRequest request, + UserInfoApiRecord userInfo + ) throws Exception { + CfgProperties property = propertyDao.getById(param.getPropertyId()); + return otherBookingService.createOtherBooking(param, request, userInfo, property); + } + + private BaseApiResponse> createOperaBooking( + BookingDto param, + HttpServletRequest request, + UserInfoApiRecord userInfo) throws Exception { + + BaseApiResponse> result = new BaseApiResponse<>(); + Date createDate = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + + String playerId = param.getPlayerId(); +// Integer blockId = param.get("blockId")!=null? Integer.valueOf(String.valueOf(param.get("blockId"))):null; + Long bookingTypeId = param.getBookingTypeId(); + String blockName = param.getBlock(); + Long propertyId = param.getPropertyId(); + Long roomId = param.getRoomId(); + String roomName = param.getRoom(); + String specialCode = param.getSpecialCode(); + JSONArray sharer = param.getSharerList(); + List dateList = param.getDateList(); + String remark = param.getRemark(); + String userId = userInfo.getUserId(); + String userName = userInfo.getUserName(); + String createdByName = userInfo.getUserName(); + String groupId = param.getGroupId(); + Long sectionId = param.getSectionId(); + PlayerProfileEntry member = param.getMember(); + List operaId = member.getNameIds(); + Long bedTypeMasterGroupId = param.getBedTypeId(); + String bedTypeName = param.getBedTypeName(); + Integer depositType = param.getDepositType(); + Integer isPost = param.getIsPost(); + Long roomTypeId = null; + CfgProperties property = propertyDao.getById(propertyId); + String miscCharge = param.getMiscCharge(); + String etaTime = param.getEtaTime(); + + List resultBookings = new ArrayList<>(); + +// BookingDateEntry dateItem = dateList.getFirst(); + + for (BookingDateEntry dateItem : dateList) { + boolean submitTag = dateItem.isSubmit(); + + if (!submitTag) { + result.setSuccess(false); + result.setData(null); + result.setMessage("submitTag is false"); + return result; + } + + List dateArr = dateItem.getDate(); + Date checkinDate = DateTimeUtil.getDateFromString(dateArr.getFirst(), "yyyy-MM-dd"); + Date checkoutDate = DateTimeUtil.getDateFromString(dateArr.getLast(), "yyyy-MM-dd"); + String checkinDateStr = DateTimeUtil.getDateByFormat(checkinDate, "yyyy-MM-dd"); + String checkoutDateStr = DateTimeUtil.getDateByFormat(checkoutDate, "yyyy-MM-dd"); + + if (property == null) { + JSONObject exption = new JSONObject(); + exption.put("errorCode", "PROPERTY_NOT_FOUND"); + exption.put("errorMessage", "[BookingService][createBooking]Property not found. propertyId=" + propertyId); + throw new Exception(JSONObject.toJSONString(exption)); + } + + // 获取Booking Type,没有的话提示前端 + if (bookingTypeId == null) { + JSONObject exption = new JSONObject(); + exption.put("errorCode", "BOOKING_TYPE_NOT_FOUND"); + exption.put("errorMessage", "[BookingService][createBooking]Booking type not found. bookingTypeId=" + bookingTypeId + ";bookingTypeName=" + blockName); + throw new Exception(JSONObject.toJSONString(exption)); + } + // RoomId没有的话提示前端 + if (roomId == null) { + JSONObject exption = new JSONObject(); + exption.put("errorCode", "ROOM_NOT_FOUND"); + exption.put("errorMessage", "[BookingService][createBooking]Room not found. roomId=" + roomId); + throw new Exception(JSONObject.toJSONString(exption)); + } + // 获取TeamStructure,没有的话提示前端 + if (sectionId == null) { + JSONObject exption = new JSONObject(); + exption.put("errorCode", "TEAM_STRUCTURE_NOT_FOUND"); + exption.put("errorMessage", "[BookingService][createBooking]Team structure not found. sectionId=" + sectionId + ";userId=" + userId); + throw new Exception(JSONObject.toJSONString(exption)); + } + + Bookings booking = new Bookings(); + booking.setPlayerId(playerId); + booking.setMemberTitle(member.getSalutation()); +// booking.setMemberFirstName(memberFirstName); + booking.setMemberLastName(member.getName()); + booking.setPropertyId(propertyId); + booking.setHotelCode(property.getHotelCode()); + booking.setChainCode(property.getCode()); + booking.setOperaProfileId(!operaId.isEmpty() ? Long.valueOf(String.valueOf(operaId.getFirst())) : null); + booking.setCreatedAt(createDate); + booking.setCreatedBy(userId); + booking.setSectionId(sectionId); + booking.setRoomId(roomId); + + booking.setRemark(remark); + booking.setBookType("0"); +// booking.setDlBlockId(blockName); + booking.setBlockCode(blockName); + booking.setBooker(userName); + booking.setBedTypeMasterGroupId(bedTypeMasterGroupId); + booking.setBedTypeName(bedTypeName); + booking.setCreatedByName(createdByName); + booking.setSharer(JSONArray.toJSONString(sharer)); + booking.setBookingTypeId(bookingTypeId); + booking.setMember(JSONObject.toJSONString(member)); + + booking.setCategory(property.getCategory()); + + booking.setEta(etaTime); + // 设置mischarge + if (StringUtils.isNotBlank(miscCharge)) + booking.setMiscCharge(miscCharge); + + String promotionCode = ""; + if (property.getId() == 1) { + promotionCode = "MM" + userId; + } else if (property.getId() == 2) { + promotionCode = "MC" + userId; + } + + if (StringUtils.isNotEmpty(promotionCode)) + booking.setPromotionCode(promotionCode); + + booking.setFeatureCode(specialCode); + booking.setRoom(roomName); + if (groupId != null) + booking.setGroupId(groupId); + + String bookRemark = dateItem.getRemark(); + if (!StringUtils.isEmpty(bookRemark)) + booking.setRemark(bookRemark); + if (isPost != null) { + dateItem.setIsPost(isPost); + } + if (depositType != null) { + dateItem.setDepositType(depositType); + } + String bookingStatus = dateItem.getBookingStatus(); + String numOfNight = String.valueOf(dateItem.getNumOfNight()); + //获取room type + booking = getRoomType(booking, roomId, checkinDate, checkinDate, bedTypeMasterGroupId); + roomTypeId = booking.getRoomTypeId(); + + + CfgTiers tier = tierDao.findByTierNameAndCategory(member.getTierName(), property.getCategory()); + CfgItemInventory item = new CfgItemInventory(); + if (tier != null && roomTypeId != null) { + item = itemDao.findByTierIdAndRoomId(tier.getId(), roomId); + } + + + if (item != null) + booking.setItemCode(item.getId() != null ? item.getAmenityPackageCode() : null); + + String blockCode = null; + + List teamOpera = new ArrayList<>(); + List exceptionOpera = new ArrayList<>(); + CfgOperaView opera = new CfgOperaView(); + CfgExceptionOperaView eopera = new CfgExceptionOperaView(); + if (property.getCategory().equalsIgnoreCase("OPERA")) { + //先从exception opera mapping拿,没有再去 opera mapping拿 + List eoperas = exceptionOperaViewDao.findByUserIdLikeAndPropertyIdAndBookingTypeId("%" + userId + "%", propertyId, bookingTypeId); + if (!eoperas.isEmpty()) { + for (CfgExceptionOperaView o : eoperas) { + for (CfgRoomTypes r : o.getOperaRoomType()) { + if (Objects.equals(r.getId(), roomTypeId)) { + exceptionOpera.add(o); + } + } + } + } + + // 筛选出符合条件的opear mapping记录,没有Opera mapping要提示前端配置 + List operas = operaViewDao.findBySectionIdAndPropertyIdAndBookingTypeId(sectionId, propertyId, bookingTypeId); + if ((operas == null || operas != null && operas.isEmpty()) && eoperas != null && eoperas.isEmpty()) { + JSONObject exption = new JSONObject(); + exption.put("errorCode", "OPERA_MAPPING_LIST_NOT_FOUND"); + exption.put("errorMessage", "[BookingService][createBooking]Opera mapping not found. teamId=" + sectionId + ";propertyId=" + propertyId + ";bookingTypeId=" + bookingTypeId); + throw new Exception(JSONObject.toJSONString(exption)); + } + for (CfgOperaView o : operas) { + for (CfgRoomTypes r : o.getOperaRoomType()) { + if (Objects.equals(r.getId(), roomTypeId)) { + teamOpera.add(o); + } + } + } + } + + + Long blockId = null; + //先从exception opera拿 + if (!exceptionOpera.isEmpty()) { + for (CfgExceptionOperaView o : exceptionOpera) { + Long startTime = Objects.requireNonNull(DateTimeUtil.getDateFromString(String.valueOf(o.getStartDate()), "yyyy-MM-dd")).getTime(); + Long endTime = DateTimeUtil.getDateFromString(String.valueOf(o.getEndDate()), "yyyy-MM-dd").getTime(); + if (startTime <= checkinDate.getTime() && endTime >= checkinDate.getTime()) { + blockCode = o.getBlockCode(); + blockId = o.getBlockId(); + eopera = o; + break; + } + } + + } + + if(blockCode==null) { + // 以checkin日期为条件筛选出对应的那条opera mapping记录 + for(CfgOperaView o :teamOpera) { + Long startTime = DateTimeUtil.getDateFromString(String.valueOf(o.getStartDate()), "yyyy-MM-dd").getTime(); + Long endTime = DateTimeUtil.getDateFromString(String.valueOf(o.getEndDate()), "yyyy-MM-dd").getTime(); + if(startTime<=checkinDate.getTime()&&endTime>=checkinDate.getTime()) { + blockCode = o.getBlockCode(); + blockId = o.getBlockId(); + opera = o; + break; + } + } + } + + if (blockCode == null) { + JSONObject exption = new JSONObject(); + exption.put("errorCode", "BLOCKCODE_NOT_FOUND"); + exption.put("errorMessage", "[BookingService][createBooking]BlockCode not found."); + throw new Exception(JSONObject.toJSONString(exption)); + } + if (eopera.getId() != null) { + booking.setMarketCode(eopera.getMarketCode().getCode()); + booking.setDlSourceId(eopera.getSourceCode().getDlSourceId()); + booking.setRatePlanCode(eopera.getRateCode().getCode()); + booking.setSourceCode(eopera.getSourceCode().getCode()); + booking.setBlockCode(blockCode); + booking.setBlockId(blockId); + } else { + booking.setMarketCode(opera.getMarketCode().getCode()); + booking.setDlSourceId(opera.getSourceCode().getDlSourceId()); + booking.setSourceCode(opera.getSourceCode().getCode()); + booking.setRatePlanCode(opera.getRateCode().getCode()); + booking.setBlockCode(blockCode); + booking.setBlockId(blockId); + } + + // ----------------------------------检查BlockCode结束---------------------------------- + List dateArray = new ArrayList<>(); + boolean isWaitlist = dateItem.getStatus() != null && dateItem.getStatus() == 1; + boolean isApproval = param.getIsApproval() != null && param.getIsApproval() == 1 && isWaitlist; + String ApprovalStatus; + if (isApproval) { + ApprovalStatus = "AP"; + } else if (isWaitlist) { + ApprovalStatus = "W"; + } else { + ApprovalStatus = "PN"; + } + + // ----------------------------------检查BlockCode结束---------------------------------- + booking.setCheckinDate(checkinDate); + booking.setCheckoutDate(checkoutDate); + booking.setNumOfNight(Integer.valueOf(numOfNight)); + booking.setApproveStatus(ApprovalStatus); + dateArray.add(dateItem); + booking.setDateList(JSONArray.toJSONString(dateArray)); + String routingReason = param.getRoutingReason(); + CfgBookingTypes cfgBookingType = bookingTypeDao.findCfgBookingTypesById(param.getBookingTypeId()); + CfgRooms room = roomDao.findById(roomId); + GetApproverRequest approverRequest = new GetApproverRequest(); + approverRequest.setBookingType(cfgBookingType.getName()); + approverRequest.setPlayerId(playerId); + approverRequest.setRoomCategory(room.getCategory()); + approverRequest.setPropertyName(property.getName()); + approverRequest.setCheckInDate(checkinDateStr); + approverRequest.setCheckOutDate(checkoutDateStr); + //检查Approver 是否存在 ApproverList中 + if (isApproval) { + BaseApiResponse approver = approvalService.getApprover(request, approverRequest); + List returnData = approver.getData().getRecords(); + LogUtil.info(BookingService.class, "RoutingReason Befor:" + routingReason); + if (StringUtils.isEmpty(routingReason)) { + routingReason = approver.getData().getStatusDescription(); + } + LogUtil.info(BookingService.class, "RoutingReason After:" + routingReason); + } + + booking.setBlockCode(blockCode); + booking.setCheckinDate(checkinDate); + booking.setCheckoutDate(checkoutDate); + booking.setNumOfNight(Integer.valueOf(numOfNight)); + booking.setApproveStatus(ApprovalStatus); + booking.setDateList(JSONArray.toJSONString(dateArray)); + + String operaComment = ""; + String stayDateForOpera = DateTimeUtil.formatOperaCommentStayDateRange( + checkinDate, checkoutDate, Integer.valueOf(numOfNight)); + // 生成给 OPERA 的 comment:根据 misCharge 是否为空决定是否包含 INC.CHRG$ 相关信息 + if (param.getMiscCharge() == null || param.getMiscCharge().trim().isEmpty()) { + operaComment = "(RM)COMP ..APP\n\n" + stayDateForOpera + ",OD," + userId; + } else { + // 这里 *** 替换为 mischarge 的实际值 + operaComment = "(RM+INC$" + param.getMiscCharge() + ")COMP ..APP\n\n" + + "INC.CHRG$" + param.getMiscCharge() + "COMP BY " + booking.getBooker() + " ..APP\n" + + stayDateForOpera + ",OD," + userId; + } + booking.setOperaComment(operaComment); + + + if (submitTag && !bookingStatus.equals("PN")) { // 这里的bookingStatus当时是用来防止后退的,迟点没用把它删了 + if (!isWaitlist) { + booking.setRemark(null); // 把不是waitlist中的remark清除 + } + Bookings saveBooking = bookingDao.save(booking); + + if (booking.getId()!=null && isApproval){ + approvalService.createApprovalRouting(booking, param.getRouterToApproverId(), param.getRouterToApproverName(), param.getRequestReasonId(), routingReason); + } + + resultBookings.add(saveBooking); + String bookingType = "CREATE_OPERA_BOOKING"; + sysLogBookingService.saveLogBooking(resultBookings, request, "", "", "Create OPERA Booking", ""); + + if (ctrlMsgSender != null && !isWaitlist && !isApproval) { + if (SysCommon.jmsRunning) { + ctrlMsgSender.sendMessage(bookingType, saveBooking); + } else { + callOWSCreateBooking(saveBooking); + } + } + } + + result.setSuccess(true); + result.setData(resultBookings); + } + return result; + } + + private BaseApiResponse> createDaylightBooking( + BookingDto param, + HttpServletRequest request, + UserInfoApiRecord userInfo) throws Exception { + + BaseApiResponse> result = new BaseApiResponse<>(); + + Date createDate = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + + String playerId = param.getPlayerId(); + Long bookingTypeId = param.getBookingTypeId(); + Long propertyId = param.getPropertyId(); + Long roomId = param.getRoomId(); + String roomName = param.getRoom(); + String dlRoomTypeId; + String specialCode = param.getSpecialCode(); + JSONArray sharer = param.getSharerList(); + List dateList = param.getDateList(); + String remark = param.getRemark(); + String userId = userInfo.getUserId(); + String userName = userInfo.getUserName(); + String createdByName = userInfo.getUserName(); + String groupId = param.getGroupId(); + Long sectionId = param.getSectionId(); + PlayerProfileEntry member = param.getMember(); + Long bedTypeMasterGroupId = param.getBedTypeId(); + String bedTypeName = param.getBedTypeName(); + Integer depositType = param.getDepositType(); + Integer isPost = param.getIsPost(); + Long roomTypeId; + + CfgProperties property = propertyDao.getById(propertyId); + + if (property == null) { + JSONObject exption = new JSONObject(); + exption.put("errorCode", "PROPERTY_NOT_FOUND"); + exption.put("errorMessage", "[BookingService][createBooking]Property not found. propertyId="+propertyId); + throw new Exception(JSONObject.toJSONString(exption)); + } + + String miscCharge = param.getMiscCharge(); + String etaTime = param.getEtaTime(); + + List resultBookings = new ArrayList<>(); + + for (BookingDateEntry dateItem : dateList) { + int numOfNight = dateItem.getNumOfNight(); + + boolean submitTag = dateItem.isSubmit(); + + if (!submitTag) { + result.setSuccess(false); + result.setData(null); + result.setMessage("submitTag is false"); + return result; + } + + List dateArr = dateItem.getDate(); + Date checkinDate = DateTimeUtil.getDateFromString(dateArr.getFirst(), "yyyy-MM-dd"); + Date checkoutDate = DateTimeUtil.getDateFromString(dateArr.getLast(), "yyyy-MM-dd"); + String checkinDateStr = DateTimeUtil.getDateByFormat(checkinDate, "yyyy-MM-dd"); + String checkoutDateStr = DateTimeUtil.getDateByFormat(checkoutDate, "yyyy-MM-dd"); + CfgRooms room = roomDao.findById(param.getRoomId()); + + List roomRoomType = room.getRoomRoomType(); + for (CfgRoomTypes type : roomRoomType) { + dlRoomTypeId = type.getDlRoomTypeId(); + if (dlRoomTypeId != null) break; + } + + // 获取Booking Type,没有的话提示前端 + if (bookingTypeId == null) { + JSONObject exption = new JSONObject(); + exption.put("errorCode", "BOOKING_TYPE_NOT_FOUND"); + exption.put("errorMessage", "[BookingService][createBooking]Booking type not found."); + throw new Exception(JSONObject.toJSONString(exption)); + } + // RoomId没有的话提示前端 + if (roomId == null) { + JSONObject exption = new JSONObject(); + exption.put("errorCode", "ROOM_NOT_FOUND"); + exption.put("errorMessage", "[BookingService][createBooking]Room not found."); + throw new Exception(JSONObject.toJSONString(exption)); + } + // Section,没有的话提示前端 + if (sectionId == null) { + JSONObject exption = new JSONObject(); + exption.put("errorCode", "SECTION_FOUND"); + exption.put("errorMessage", "[BookingService][createBooking]Section not found. userId="+userId); + throw new Exception(JSONObject.toJSONString(exption)); + } + + Bookings booking = new Bookings(); + booking.setPlayerId(playerId); + booking.setMemberTitle(member.getSalutation()); +// booking.setMemberFirstName(memberFirstName); + booking.setMemberLastName(member.getName()); + booking.setPropertyId(propertyId); + booking.setHotelCode(property.getCode()); + booking.setChainCode(property.getCode()); + booking.setCreatedAt(createDate); + booking.setCreatedBy(userId); + booking.setSectionId(sectionId); + booking.setRoomId(roomId); + booking.setRemark(remark); + booking.setBookType("0"); + booking.setBooker(userName); + booking.setBedTypeMasterGroupId(bedTypeMasterGroupId); + booking.setBedTypeName(bedTypeName); + booking.setCreatedByName(createdByName); + booking.setSharer(JSONArray.toJSONString(sharer)); + booking.setBookingTypeId(bookingTypeId); + booking.setMember(JSONObject.toJSONString(member)); + booking.setCategory(property.getCategory()); + + // 设置etaTime + if (StringUtils.isNotBlank(etaTime)) + booking.setEta(etaTime); + + // 设置mischarge + if (StringUtils.isNotBlank(miscCharge)) + booking.setMiscCharge(miscCharge); + + String promotionCode = ""; + if (property.getId() == 1) { + promotionCode = "MM" + userId; + } else if (property.getId() == 2) { + promotionCode = "MC" + userId; + } + + if (StringUtils.isNotEmpty(promotionCode)) + booking.setPromotionCode(promotionCode); + + booking.setFeatureCode(specialCode); + booking.setRoom(roomName); + if (groupId != null) + booking.setGroupId(groupId); + + //判断Edit的日期是否超过CMS设置 + CfgSettings maxBookingStayDays = settingService.getSettingByKey(SysConstants.MAX_BOOKING_STAY_DAYS); + + if(maxBookingStayDays != null && numOfNight > Integer.parseInt(maxBookingStayDays.getKeyValues())) { + result.setSuccess(false); + result.setMessage("Exceeded Maximum Booking Stay Days"); + return result; + } + + String bookRemark = dateItem.getRemark(); + if (!StringUtils.isEmpty(bookRemark)) + booking.setRemark(bookRemark); + if (isPost != null) { + dateItem.setIsPost(isPost); + } + if (depositType != null) { + dateItem.setDepositType(depositType); + } + String bookingStatus = dateItem.getBookingStatus(); + + //获取room type + booking = getRoomType(booking, roomId, checkinDate, checkinDate, bedTypeMasterGroupId); + roomTypeId = booking.getRoomTypeId(); + + + CfgTiers tier = tierDao.findByTierNameAndCategory(member.getTierName(), property.getCategory()); + CfgItemInventory item = new CfgItemInventory(); + if (tier != null && roomTypeId != null) { + item = itemDao.findByTierIdAndRoomId(tier.getId(), roomId); + } + + + if (item != null) + booking.setItemCode(item.getId() != null ? item.getAmenityPackageCode() : null); + + String blockCode = null; + // ----------------------------------如果是Daylight Property需要检查---------------------------------- + + List cfgDaylightViews = new ArrayList<>(); + List eDaylightViewList = new ArrayList<>(); + CfgDaylightView daylightView = new CfgDaylightView(); + CfgExceptionDaylightView eDaylightView = new CfgExceptionDaylightView(); + + //先从exception opera mapping拿,没有再去 opera mapping拿 + List eDaylightViewListTemp = exceptionDaylightViewDao.findByUserIdLikeAndPropertyIdAndBookingTypeId("%" + userId + "%", propertyId, bookingTypeId); + log.info("[createBooking][DAYLIGHT] exceptionDaylightView query done, userId={}, propertyId={}, bookingTypeId={}, resultCount={}", userId, propertyId, bookingTypeId, eDaylightViewListTemp.size()); + if (!eDaylightViewListTemp.isEmpty()) { + for (CfgExceptionDaylightView o : eDaylightViewListTemp) { + for (CfgRoomTypes r : o.getDaylightRoomType()) { + if (Objects.equals(r.getId(), roomTypeId)) { + eDaylightViewList.add(o); + } + } + } + } + + log.info("[createBooking][DAYLIGHT] exceptionDaylightView filtered by roomTypeId, matchCount={}, roomTypeId={}", eDaylightViewList.size(), roomTypeId); + // 筛选出符合条件的opear mapping记录,没有Opera mapping要提示前端配置 + List daylightViewList = daylightViewDao.findBySectionIdAndPropertyIdAndBookingTypeId(userInfo.getSectionId(), propertyId, bookingTypeId); + log.info("[createBooking][DAYLIGHT] daylightView query done, sectionId={}, propertyId={}, bookingTypeId={}, resultCount={}", userInfo.getSectionId(), propertyId, bookingTypeId, daylightViewList != null ? daylightViewList.size() : 0); + if ((daylightViewList == null || (daylightViewList != null && daylightViewList.isEmpty())) && (eDaylightViewListTemp == null || (eDaylightViewListTemp != null && eDaylightViewListTemp.isEmpty()))) { + JSONObject exption = new JSONObject(); + exption.put("errorCode", "DAYLIGHT_MAPPING_LIST_NOT_FOUND"); + exption.put("errorMessage", "[BookingService][createBooking]Daylight mapping not found. sectionId=" + userInfo.getSectionId() + ";propertyId=" + propertyId + ";bookingTypeId=" + bookingTypeId); + throw new Exception(JSONObject.toJSONString(exption)); + } + for (CfgDaylightView o : daylightViewList) { + for (CfgRoomTypes r : o.getDaylightRoomType()) { + if (Objects.equals(r.getId(), roomTypeId)) { + cfgDaylightViews.add(o); + } + } + } + + if (cfgDaylightViews.isEmpty()) { + log.warn("[createBooking][DAYLIGHT] daylightView found but no matching roomTypeId, sectionId={}, propertyId={}, bookingTypeId={}, roomTypeId={}", userInfo.getSectionId(), propertyId, bookingTypeId, roomTypeId); + JSONObject exption = new JSONObject(); + exption.put("errorCode", "DAYLIGHT_MAPPING_ROOM_TYPE_NOT_FOUND"); + exption.put("errorMessage", "[BookingService][createBooking]Daylight mapping found but no matching roomType. sectionId=" + userInfo.getSectionId() + ";propertyId=" + propertyId + ";bookingTypeId=" + bookingTypeId + ";roomTypeId=" + roomTypeId); + throw new Exception(JSONObject.toJSONString(exption)); + } + + Long blockId = null; + //先从exception opera拿 + if (eDaylightViewList!=null && !eDaylightViewList.isEmpty()) { + log.info("[createBooking][DAYLIGHT] Entering exceptionDaylightView date matching, eDaylightViewListCount={}, checkinDate={}", eDaylightViewList.size(), checkinDateStr); + for (CfgExceptionDaylightView o : eDaylightViewList) { + Long startTime = DateTimeUtil.getDateFromString(String.valueOf(o.getStartDate()), "yyyy-MM-dd").getTime(); + Long endTime = DateTimeUtil.getDateFromString(String.valueOf(o.getEndDate()), "yyyy-MM-dd").getTime(); + if (startTime <= checkinDate.getTime() && endTime >= checkinDate.getTime()) { + log.info("[createBooking][DAYLIGHT] exceptionDaylightView date matched, startDate={}, endDate={}, blockCode={}", o.getStartDate(), o.getEndDate(), o.getBlockCodeName()); + blockCode = o.getBlockCodeName(); + blockId = o.getBlockCodeId(); + eDaylightView = o; + break; + }else{ + log.warn("[createBooking][DAYLIGHT] exceptionDaylightView date mismatch, startDate={}, endDate={}, checkinDate={}, will throw DAYLIGHT_EXCEPTION_EXPIRED", o.getStartDate(), o.getEndDate(), checkinDateStr); + JSONObject exption = new JSONObject(); + exption.put("errorCode", "DAYLIGHT_EXCEPTION_EXPIRED"); + exption.put("errorMessage", "[BookingService][createBooking]The daylight exception has expired. sectionId=" + userInfo.getSectionId() + ";propertyId=" + propertyId + ";bookingTypeId=" + bookingTypeId); + throw new Exception(JSONObject.toJSONString(exption)); + } + } + } + + if(blockCode==null) { + log.info("[createBooking][DAYLIGHT] exceptionDaylightView no blockCode matched, falling back to daylightView, cfgDaylightViewsCount={}", cfgDaylightViews.size()); + // 以checkin日期为条件筛选出对应的那条opera mapping记录 + for(CfgDaylightView o :cfgDaylightViews) { + long startTime = DateTimeUtil.getDateFromString(o.getStartDate(), "yyyy-MM-dd").getTime(); + long endTime = DateTimeUtil.getDateFromString(o.getEndDate(), "yyyy-MM-dd").getTime(); + if(startTime<=checkinDate.getTime()&&endTime>=checkinDate.getTime()) { + log.info("[createBooking][DAYLIGHT] daylightView date matched, startDate={}, endDate={}, blockCode={}", o.getStartDate(), o.getEndDate(), o.getBlockCodeName()); + blockCode = o.getBlockCodeName(); + blockId = o.getBlockCodeId(); + daylightView = o; + break; + } + } + if (blockCode == null) { + log.error("[createBooking][DAYLIGHT] daylightView also no blockCode matched, checkinDate={}, cfgDaylightViewsCount={}", checkinDateStr, cfgDaylightViews.size()); + JSONObject exption = new JSONObject(); + exption.put("errorCode", "BLOCK_CODE_NOT_FOUND"); + exption.put("errorMessage", "[BookingService][createBooking]The block code not found. blockCodeId=" + blockId); + throw new Exception(JSONObject.toJSONString(exption)); + } + } + + if (eDaylightView.getId() != null) { + log.info("[createBooking][DAYLIGHT] Using exceptionDaylightView data, blockCode={}, blockId={}", blockCode, blockId); + booking.setMarketCode(eDaylightView.getMarketCode().getCode()); + booking.setDlSourceId(eDaylightView.getSourceCode().getDlSourceId()); + booking.setRatePlanCode(eDaylightView.getRateCode().getCode()); + booking.setBlockId(blockId); + booking.setDlBlockId(eDaylightView.getBlockCode().getDlBlockId()); + booking.setSourceCode(eDaylightView.getSourceCode().getCode()); + booking.setBlockCode(eDaylightView.getBlockCode().getCode()); + } else { + log.info("[createBooking][DAYLIGHT] Using daylightView data, blockCode={}, blockId={}", blockCode, blockId); + booking.setMarketCode(daylightView.getMarketCode().getCode()); + booking.setDlSourceId(daylightView.getSourceCode().getDlSourceId()); + booking.setRatePlanCode(daylightView.getRateCode().getCode()); + booking.setBlockId(blockId); + booking.setDlBlockId(daylightView.getBlockCode().getDlBlockId()); + booking.setSourceCode(daylightView.getSourceCode().getCode()); + booking.setBlockCode(daylightView.getBlockCode().getCode()); + } + // ----------------------------------检查BlockCode结束---------------------------------- + + List dateArray = new ArrayList<>(); + boolean isWaitlist = dateItem.getStatus() != null && dateItem.getStatus() == 1; + boolean isApproval = param.getIsApproval() != null && param.getIsApproval() == 1 && isWaitlist; + + CfgBookingTypes cfgBookingType = bookingTypeDao.findCfgBookingTypesById(param.getBookingTypeId()); + GetApproverRequest approverRequest = new GetApproverRequest(); + approverRequest.setBookingType(cfgBookingType.getName()); + approverRequest.setPlayerId(playerId); + approverRequest.setRoomCategory(room.getCategory()); + approverRequest.setPropertyName(property.getName()); + approverRequest.setCheckInDate(checkinDateStr); + approverRequest.setCheckOutDate(checkoutDateStr); + String routingReason = param.getRoutingReason(); + String approvalStatus; + + if (isApproval) { + approvalStatus = "AP"; + } else if (isWaitlist) { + approvalStatus = "W"; + } else { + approvalStatus = "PN"; + } + if (isApproval) { + BaseApiResponse approver = approvalService.getApprover(request, approverRequest); + List returnData = approver.getData().getRecords(); + LogUtil.info(BookingService.class, "RoutingReason Befor:" + routingReason); + if (StringUtils.isEmpty(routingReason)) { + routingReason = approver.getData().getStatusDescription(); + } + LogUtil.info(BookingService.class, "RoutingReason After:" + routingReason); + } + + booking.setCheckinDate(checkinDate); + booking.setCheckoutDate(checkoutDate); + booking.setNumOfNight(numOfNight); + booking.setApproveStatus(approvalStatus); + dateArray.add(dateItem); + booking.setDateList(JSONArray.toJSONString(dateArray)); + + if (!isWaitlist) { + booking.setDlExternalNo("CL-" + UUID.randomUUID().toString().replace("-", "")); + } + + if (!bookingStatus.equals("PN")) { // 这里的bookingStatus当时是用来防止后退的,迟点没用把它删了 + if(!isWaitlist) { + booking.setRemark(null); // 把不是waitlist中的remark清除 + } + //再Daylight Create Reservation之后再去saveBooking + Bookings saveBooking = bookingDao.save(booking); + if (booking.getId()!=null && isApproval){ + approvalService.createApprovalRouting(booking, param.getRouterToApproverId(), param.getRouterToApproverName(), param.getRequestReasonId(), routingReason); + } + + resultBookings.add(saveBooking); + String bookingType = "CREATE_DAYLIGHT_BOOKING"; + sysLogBookingService.saveLogBooking(resultBookings, request, "", "", "Create DAYLIGHT Booking",""); + + if(ctrlMsgSender != null && !isWaitlist && !isApproval) { + if(SysCommon.jmsRunning) { + ctrlMsgSender.sendMessage(bookingType, saveBooking); + }else { + callDaylightUpsertReservation(saveBooking, "CREATE_BOOKING"); + } + } + } + } + + result.setSuccess(true); + result.setData(resultBookings); + + return result; + } + + public BaseApiResponse> callDaylightUpsertReservation(Bookings bookings, String type) throws Exception { + BaseApiResponse> processResult = new BaseApiResponse<>(); + + ReservationRequestDTO reservationRequestDTO = + this.buildUpsertReservationRequest(bookings); + + ReservationDTO reservationDTO = new ReservationDTO(); + reservationDTO.setRefId("res_1"); + + List result = bookingMapper.convertJsonToDateList(bookings.getDateList()); + String userId = bookings.getCreatedBy(); + Long roomTypeId = bookings.getRoomTypeId(); + CfgProperties property = propertyDao.getById(bookings.getPropertyId()); + + Long bookingTypeId = bookings.getBookingTypeId(); + CfgBookingTypes bookingType = bookingTypeDao.findById(bookingTypeId).orElse(null); + String bookingTypeName = bookingType.getName(); + + CfgBlockCodes blockCodeById = blockCodeDao.findById(bookings.getBlockId()).orElse(null); + +// if (blockCodeById == null) { +// bookings.setApproveStatus("F"); +// bookings.setErrorMessage("Block code not found"); +// bookings.setTryTime(5); +// bookingDao.save(bookings); +// processResult.setSuccess(false); +// processResult.setMessage("[BookingService][createBooking]BlockCode not found."); +// return processResult; +// } + reservationDTO.setBlockId(blockCodeById.getDlBlockId()); + + List resultBookings = new ArrayList<>(); + + BookingDateEntry dateEntry = result.getFirst(); + + boolean submitTag = dateEntry.isSubmit(); + + Integer isPostIM = dateEntry.getIsPost(); + Integer depositTypeIM = dateEntry.getDepositType(); + +// if (!submitTag) { +// bookings.setApproveStatus("F"); +// bookings.setErrorMessage("Submit is false"); +// bookings.setTryTime(5); +// bookingDao.save(bookings); +// processResult.setSuccess(false); +// processResult.setMessage("[BookingService][callDaylightCreateReservationNew]SubmitTag is false"); +// processResult.setData(resultBookings); +// return processResult; +// } + + List dateArr = dateEntry.getDate(); + + Date checkinDate = DateTimeUtil.getDateFromString(String.valueOf(dateArr.getFirst()), "yyyy-MM-dd"); + Date checkoutDate = DateTimeUtil.getDateFromString(String.valueOf(dateArr.getLast()), "yyyy-MM-dd"); + String checkinDateStr = DateTimeUtil.getDateByFormat(checkinDate, "yyyy-MM-dd"); + String checkoutDateStr = DateTimeUtil.getDateByFormat(checkoutDate, "yyyy-MM-dd"); + + reservationDTO.setArrivalDate(checkinDateStr); + reservationDTO.setDepartureDate(checkoutDateStr); + + List preferences = new ArrayList<>(); + if (bookings.getFeatureCode() != null) { + String[] list = bookings.getFeatureCode().split(","); + for (String code : list) { + ReservationDTO.PreferenceDTO pref = new ReservationDTO.PreferenceDTO(); + CfgRoomFeatures roomFeatures = roomFeatureDao.getByDaylightCode(code); + pref.setId(roomFeatures.getDlAttributeId()); + preferences.add(pref); + } + } + if (CollectionUtils.isNotEmpty(preferences)) + reservationDTO.setPreferences(preferences); + + String guaranteeTypeId = null; + List guaranteeTypeResult = dlService.dayLightGetGuaranteeType(property.getDlPropertyId()); + + if (CollectionUtils.isEmpty(guaranteeTypeResult)) { + bookings.setApproveStatus("F"); + bookings.setErrorMessage("Guarantee type not found."); + bookingDao.save(bookings); + processResult.setSuccess(false); + processResult.setMessage("Guarantee Type not found"); + return processResult; + } + + for (GuaranteeTypeResponse guaranteeType : guaranteeTypeResult) { + if ("CGTD".equalsIgnoreCase(guaranteeType.getCode())) { + guaranteeTypeId = guaranteeType.getId(); + bookings.setDlGuaranteeTypeId(guaranteeTypeId); + break; + } + } + + if (StringUtils.isBlank(guaranteeTypeId)) { + guaranteeTypeId = guaranteeTypeResult.getFirst().getId(); + bookings.setDlGuaranteeTypeId(guaranteeTypeId); + } + + reservationDTO.setGuaranteeTypeId(guaranteeTypeId); + + String channelId = null; + List channelResult = dlService.dayLightGetDistributeChannel(property.getDlPropertyId()); + + if (CollectionUtils.isEmpty(channelResult)) { + bookings.setApproveStatus("F"); + bookings.setErrorMessage("Channel not found"); + bookingDao.save(bookings); + processResult.setSuccess(false); + processResult.setMessage("Channel not found"); + return processResult; + } + + if (CollectionUtils.isNotEmpty(channelResult)) { + for (DistributionChannelResponse distributionChannel : channelResult) { + if ("MCRM".equalsIgnoreCase(distributionChannel.getCode())) { + channelId = distributionChannel.getId(); + bookings.setDlChannelId(channelId); + break; + } + } + if (StringUtils.isBlank(channelId)) { + channelId = channelResult.getFirst().getId(); + bookings.setDlChannelId(channelId); + } + } + reservationDTO.setChannelId(channelId); + + List daylightViewList = daylightViewDao.findBySectionPropertyBookingTypeRoomType( + bookings.getSectionId(), + bookings.getPropertyId(), + bookings.getBookingTypeId(), + roomTypeId + ); + +// if (CollectionUtils.isEmpty(daylightViewList)) { +// bookings.setApproveStatus("F"); +// bookings.setErrorMessage("Daylight view not found"); +// bookingDao.save(bookings); +// log.warn("Not Found DaylightView, sectionId={}, propertyId={}, bookingTypeId={}, roomTypeId={}", +// bookings.getSectionId(), bookings.getPropertyId(), bookings.getBookingTypeId(), roomTypeId); +// processResult.setSuccess(false); +// processResult.setMessage("Not Found DaylightView"); +// processResult.setData(resultBookings); +// return processResult; +// } + + CfgDaylightView daylightView = daylightViewList.getFirst(); + + CfgRateCodes rateCode = rateCodeDao.findById(daylightView.getRateCodeId()).orElse(null); +// if (rateCode == null) { +// bookings.setApproveStatus("F"); +// bookings.setErrorMessage("Rate Code not found"); +// bookingDao.save(bookings); +// processResult.setSuccess(false); +// processResult.setMessage("Not Found Rate Code"); +// return processResult; +// } + bookings.setRatePlanCode(rateCode.getCode()); + + PlayerProfileEntry memberItem = bookingMapper.convertJsonToMember(bookings.getMember()); + + BaseApiResponse> profileListResponse = + dlService.dayLightGetProfileByPlayerId(bookings.getPlayerId()); + + ProfileDetailResponse profileDetailResponse; + ProfileMemberships profileMemberships; + + // 先假设百分百查出来profile by Mauve 2026-07-08 + // 这里的 TO'DO 完成了 by Mauve 2026-07-10 + if (CollectionUtils.isNotEmpty(profileListResponse.getData())) { + profileDetailResponse = profileListResponse.getData().getFirst(); + + bookings.setDlProfileId(profileDetailResponse.getId()); + profileMemberships = profileDetailResponse.getMemberships().getFirst(); + + ReservationMembershipDTO rmDto = new ReservationMembershipDTO(); + rmDto.setId(profileMemberships.getId()); + rmDto.setUseDefaultMembership(false); + reservationDTO.setMembership(rmDto); + + ReservationDTO.GuestDTO guestDTO = new ReservationDTO.GuestDTO(); + guestDTO.setId(profileDetailResponse.getId()); + reservationDTO.setGuest(guestDTO); + + // 这里说明 main player 在 daylight 不存在,会create 一个新的 profile in daylight + // 并set 一个 embedded 进去 + } else { + IndividualDTO guestIndividual = IndividualDTO.buildNewProfileWithPlayerId( + bookings.getPlayerId(), + memberItem.getName(), + "gusmem_1", + "gus_1", + memberItem.getTierName() + ); + + profileMemberships = new ProfileMemberships(); + + ProfileMemberships.LevelCode temp = new ProfileMemberships.LevelCode(); + temp.setCode(guestIndividual.getMemberLevelCode()); + profileMemberships.setLevelCode(temp); + + ReservationRequestDTO.EmbeddedDTO embeddedDTO = new ReservationRequestDTO.EmbeddedDTO(); + + List individualDTOList = new ArrayList<>(); + individualDTOList.add(guestIndividual); + + embeddedDTO.setIndividuals(individualDTOList); + + reservationRequestDTO.setEmbedded(embeddedDTO); + + // 因为没有 profile in daylight,所以这里应该用refId而不是id + ReservationMembershipDTO rmDto = new ReservationMembershipDTO(); + rmDto.setRefId(guestIndividual.getMemRefId()); + rmDto.setUseDefaultMembership(false); + reservationDTO.setMembership(rmDto); + + ReservationDTO.GuestDTO guestDTO = new ReservationDTO.GuestDTO(); + guestDTO.setId(guestIndividual.getRefId()); + reservationDTO.setGuest(guestDTO); + } + + // 通过tier 添加 purchase element + CfgTiers byDaylightTier = tierDao.findByDaylightTier(ProfileTierEnums.fromIgtPMLevel(memberItem.getTierName())); + + CfgItemInventory byTierIdAndRoomIdAndPropertyId = null; + if (byDaylightTier != null && byDaylightTier.getId() != null) { + byTierIdAndRoomIdAndPropertyId = itemDao.findByTierIdAndRoomIdAndPropertyId( + byDaylightTier.getId(), + bookings.getRoomId(), + bookings.getPropertyId() + ); + } + if (byTierIdAndRoomIdAndPropertyId != null && byTierIdAndRoomIdAndPropertyId.getDlPurchaseElementId() != null) { + bookings.setDlPurchaseElementId(byTierIdAndRoomIdAndPropertyId.getDlPurchaseElementId()); + + PurchaseElementsWithInventoryItemsDTO.PurchaseElementDTO.PurchaseBreakdownDTO purchaseBreakdownDTO = + new PurchaseElementsWithInventoryItemsDTO.PurchaseElementDTO.PurchaseBreakdownDTO(); + + PurchaseElementsWithInventoryItemsDTO.PurchaseElementDTO purchaseElementDTO = + new PurchaseElementsWithInventoryItemsDTO.PurchaseElementDTO(); + + PurchaseElementsWithInventoryItemsDTO purchaseElementsWithInventoryItemsDTO = + new PurchaseElementsWithInventoryItemsDTO(); + + purchaseBreakdownDTO.setFrom(checkinDateStr); + purchaseBreakdownDTO.setTo(checkinDateStr); + purchaseBreakdownDTO.setGuestCount(1); + purchaseBreakdownDTO.setQuantity(1); + + purchaseElementDTO.setBreakdown(List.of(purchaseBreakdownDTO)); + purchaseElementDTO.setDateAnchor("Arrival"); + purchaseElementDTO.setPurchaseElementId(byTierIdAndRoomIdAndPropertyId.getDlPurchaseElementId()); + + purchaseElementsWithInventoryItemsDTO.setPurchaseElements(List.of(purchaseElementDTO)); + + reservationDTO.setPurchaseElementsWithInventoryItems(purchaseElementsWithInventoryItemsDTO); + } + + String etaTime = bookings.getEta(); + + if (StringUtils.isNotBlank(etaTime)) { + String[] splitETATime = etaTime.split(":"); + + String eta = null; + if (splitETATime.length == 2) { + eta = checkinDateStr + "T" + splitETATime[0] + ":" + splitETATime[1] + ":00"; + } else if (splitETATime.length == 3) { + eta = checkinDateStr + "T" + splitETATime[0] + ":" + splitETATime[1] + ":" + splitETATime[2]; + } + + if (StringUtils.isNotBlank(eta)) { + reservationDTO.setEta(eta); + } + } + + CfgRoomTypes roomType = roomTypeDao.findById(bookings.getRoomTypeId()); +// if (roomType == null) { +// bookings.setApproveStatus("F"); +// bookings.setErrorMessage("Room Type not found"); +// bookingDao.save(bookings); +// processResult.setSuccess(false); +// processResult.setMessage("Room Type not found"); +// return processResult; +// } + String dlRoomTypeId = roomType.getDlRoomTypeId(); + ReservationDTO.AllocationDTO allocationDTO = new ReservationDTO.AllocationDTO(); + allocationDTO.setRoomTypeId(dlRoomTypeId); + reservationDTO.setAllocation(allocationDTO); + + CfgSourceCodes sourceCode = sourceCodeDao.findById(daylightView.getSourceCodeId()).orElse(null); +// if (sourceCode == null) { +// bookings.setApproveStatus("F"); +// bookings.setErrorMessage("Source code not found"); +// bookingDao.save(bookings); +// processResult.setSuccess(false); +// processResult.setMessage("Source code not found"); +// return processResult; +// } + + reservationDTO.setSourceId(sourceCode.getDlSourceId()); + bookings.setDlSourceId(sourceCode.getDlSourceId()); + + if ("IM".equalsIgnoreCase(bookingTypeName) && isPostIM == 0) { + reservationDTO.setNoPost(true); + } else { + reservationDTO.setNoPost(StringUtils.isBlank(bookings.getMiscCharge())); + } + + CfgMarketCodes marketCode = marketCodeDao.findById(daylightView.getMarketCodeId()).orElse(null); +// if (marketCode == null) { +// bookings.setApproveStatus("F"); +// bookings.setErrorMessage("Market code not found"); +// bookingDao.save(bookings); +// processResult.setSuccess(false); +// processResult.setMessage("marketCode not found"); +// return processResult; +// } + bookings.setMarketCode(marketCode.getCode()); + + ReservationDTO.BreakdownDTO breakdownDTO = new ReservationDTO.BreakdownDTO(); + breakdownDTO.setFromDate(checkinDateStr); + breakdownDTO.setToDate(checkoutDateStr); + breakdownDTO.setMarketSegmentId(marketCode.getDlMarketSegmentId()); + + ReservationDTO.BreakdownDTO.GuestCountDTO guestCountDTO = + new ReservationDTO.BreakdownDTO.GuestCountDTO(); + + guestCountDTO.setCount(1); + + SysAgebucket sysAgebucket = agebucketService.getSysAgebucket(property.getDlPropertyId()); + guestCountDTO.setAgeBucketId(sysAgebucket.getDlAgeBucketId()); + breakdownDTO.setGuests(List.of(guestCountDTO)); + + ReservationDTO.BreakdownDTO.RatePricingDetailsDTO ratePricingDetailsDTO = + new ReservationDTO.BreakdownDTO.RatePricingDetailsDTO(); + ratePricingDetailsDTO.setRatePlanId(rateCode.getDlRatePlanId()); + ratePricingDetailsDTO.setRoomTypeToChargeId(roomType.getDlRoomTypeId()); + + 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 (bookings.getWaitlistId() != null) { + customFields.put("App_Rea", "APP"); + customFields.put("Approver", bookings.getApprovedBy()); + } + + String sharerString = bookings.getSharer(); + JSONArray sharers = JSONArray.parseArray(sharerString); + + if (CollectionUtils.isNotEmpty(sharers)) { + + // TO'DO 假设一定有sharer在daylight by Mauve 2026-07-09 + // 这个 TO'DO 完成了 by Mauve 2026-07-13 + List dlSharers = new ArrayList<>(); + + for (int i = 0; i < sharers.size(); i++) { + JSONObject sharer = sharers.getJSONObject(i); + + String sharerId = sharer.getString("playerId"); + + BaseApiResponse> serviceResult = dlService.dayLightGetProfileByPlayerId(sharerId); + List returnData = serviceResult.getData(); + + boolean isSharerOnDaylight = serviceResult.isSuccess() && CollectionUtils.isNotEmpty(returnData); + + // 如果sharer profile在daylight是存在的,就直接加进去 + if (isSharerOnDaylight) { + ProfileDetailResponse sharerProfile = returnData.getFirst(); + AccompanyingGuestDTO accompanyingGuest = new AccompanyingGuestDTO(); + + accompanyingGuest.setProfileId(sharerProfile.getId()); + + dlSharers.add(accompanyingGuest); + + continue; + } + + // 走到这里说明在daylight没有这个sharer profile的相关信息 + String sharerName = sharer.getString("name"); + + IndividualDTO individualDTO; + if (StringUtils.isEmpty(sharerId)) { + individualDTO = IndividualDTO.buildNewProfileWithoutPlayerId( + sharerName, + "sha_" + i + ); + } else { + individualDTO = IndividualDTO.buildNewProfileWithPlayerId( + sharerId, + sharerName, + "shamem_" + i, + "sha_" + i, + sharer.getString("tierName") + ); + } + + // 如果 main player 在 daylight 不存在,则在上面的相关方法会set一个embedded进去 + // 如果 main player 在 daylight 存在,则在上面的相关方法不会Set embedded + if (reservationRequestDTO.getEmbedded() == null) { + + reservationRequestDTO.setEmbedded(new ReservationRequestDTO.EmbeddedDTO()); + } + + ReservationRequestDTO.EmbeddedDTO embeddedDTO = reservationRequestDTO.getEmbedded(); + + List individualList = embeddedDTO.getIndividuals(); + + if (CollectionUtils.isEmpty(individualList)) { + individualList = new ArrayList<>(); + } + + individualList.add(individualDTO); + + embeddedDTO.setIndividuals(individualList); + + AccompanyingGuestDTO newSharer = new AccompanyingGuestDTO(); + newSharer.setProfileId("sha_" + i); + + dlSharers.add(newSharer); + } + + reservationDTO.setAccompanyingGuests(dlSharers); + } + + ReservationDTO.CustomFieldDTO customFieldDTO = + new ReservationDTO.CustomFieldDTO(); + + customFieldDTO.setLocation("ReservationHeader"); + customFieldDTO.setValue(JSON.toJSONString(customFields)); + reservationDTO.setCustomFields(List.of(customFieldDTO)); + + ReservationDTO.ReservationFlowControlDTO resFlowControlDTO = + new ReservationDTO.ReservationFlowControlDTO(); + resFlowControlDTO.setUpsertNotesStrategy("Merge"); + resFlowControlDTO.setExternalIdsCollectionBehaviour("Overwrite"); + resFlowControlDTO.setPreferencesCollectionBehaviour("Merge"); + reservationDTO.setFlowControl(resFlowControlDTO); + + reservationDTO.setUseProfileBillingRules(false); + + String operaComment; + String stayDateForOpera = DateTimeUtil.formatOperaCommentStayDateRange( + checkinDate, checkoutDate, bookings.getNumOfNight()); + + if ("CREATE_BOOKING".equalsIgnoreCase(type)) { + + if ("IM".equalsIgnoreCase(bookingTypeName)) { + operaComment = buildIMComment(bookings); + } else { + String miscCharge = bookings.getMiscCharge(); + // 生成给 OPERA 的 comment:根据 miscCharge 是否为空决定是否包含 INC.CHRG$ 相关信息 + if (miscCharge == null || miscCharge.trim().isEmpty()) { + operaComment = "(RM)COMP ..APP\n\n"+ stayDateForOpera+",OD,"+userId; + } else { + // 这里 *** 替换为 miscCharge 的实际值 + operaComment = "(RM+INC$" + miscCharge + ")COMP ..APP\n\n" + + "INC.CHRG$" + miscCharge + "COMP BY "+bookings.getBooker()+" ..APP\n" + + stayDateForOpera+",OD,"+userId; + } + } + + bookings.setOperaComment(operaComment); + + ReservationDTO.ReservationEmbeddedDTO.NoteDTO noteDto = + new ReservationDTO.ReservationEmbeddedDTO.NoteDTO(); + ReservationDTO.ReservationEmbeddedDTO reservationEmbeddedDTO = + new ReservationDTO.ReservationEmbeddedDTO(); + + noteDto.setRefId("not_1"); + noteDto.setTypeCode("RES"); + noteDto.setContent(operaComment); + + reservationEmbeddedDTO.setNotes(List.of(noteDto)); + + reservationDTO.setEmbedded(reservationEmbeddedDTO); + } + + bookingDao.save(bookings); + + reservationRequestDTO.setReservations(List.of(reservationDTO)); + + if ("CREATE_BOOKING".equalsIgnoreCase(type) && !bookings.getApproveStatus().contains("W")) { + BaseApiResponse createResponse = + dlService.daylightUpsertReservationNew(reservationRequestDTO, property.getDlPropertyId()); + + if (!createResponse.isSuccess()) { + Integer trytime = bookings.getTryTime()==null?0:(bookings.getTryTime()+1); + bookings.setApproveStatus("F"); + bookings.setTryTime(trytime); + bookings.setErrorMessage(createResponse.getMessage()); + bookings.setFailedAt(DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss")); + bookings.setProcessStatus(0); + + bookingDao.save(bookings); + + if(bookings.getWaitlistId() != null) { + Bookings waitlistBooking = bookingDao.findById(bookings.getWaitlistId()).orElse(null); + waitlistBooking.setConfirmationNo(bookings.getConfirmationNo()); + waitlistBooking.setApproveStatus("WF"); + waitlistBooking.setUpdatedAt(DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss")); + bookingDao.save(waitlistBooking); + } + + processResult.setSuccess(false); + processResult.setMessage(createResponse.getMessage()); + log.warn(createResponse.getMessage()); + + return processResult; + } + + String reservationId = createResponse.getData().getString("reservationId"); + String confirmationNumber = createResponse.getData().getString("confirmationNumber"); + + DaylightReservationResponse daylightReservationByDlId = + dlService.getDaylightReservationByDlId(reservationId, property.getDlPropertyId()); + + bookings.setDlAccountId(daylightReservationByDlId.getAccountId()); + bookings.setDlReservationId(reservationId); + bookings.setConfirmationNo(confirmationNumber); + bookings.setLastOperaStatus("RESERVED"); + bookings.setApproveStatus("N"); + + bookingDao.save(bookings); + + dlService.createDaylightCompRule( + daylightReservationByDlId.getAccountId(), + daylightReservationByDlId.getProfileId(), + property.getDlPropertyId(), + userId, + checkinDateStr, + checkoutDateStr, + daylightViewList, + bookings.getMiscCharge() + ); + + //Create Reservation 后处理WaitListBooking + if (bookings.getWaitlistId() != null) { + Bookings waitlistBooking = bookingDao.findById(bookings.getWaitlistId()).orElse(null); + waitlistBooking.setConfirmationNo(bookings.getConfirmationNo()); + waitlistBooking.setApproveStatus("WF"); + waitlistBooking.setUpdatedAt(DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss")); + bookingDao.save(waitlistBooking); + } + + //update Approval Booking + if(bookings.getApprovalBookingId()!=null) { + Bookings approvalBooking = bookingDao.findById(Long.valueOf(bookings.getApprovalBookingId())).orElse(null); + approvalBooking.setConfirmationNo(bookings.getConfirmationNo()); + approvalBooking.setUpdatedAt(DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss")); + bookingDao.save(approvalBooking); + } + + processResult.setSuccess(true); + processResult.setMessage("Create reservation success"); + + } else if ("SUBMIT_ETA".equalsIgnoreCase(type)) { + BaseApiResponse createResponse = + dlService.daylightUpsertReservationNew(reservationRequestDTO, property.getDlPropertyId()); + + if (createResponse.isSuccess()) { + processResult.setSuccess(true); + processResult.setMessage("Submit ETA success"); + } else { + processResult.setSuccess(false); + processResult.setMessage("Submit ETA fail"); + log.warn("Submit ETA fail"); + } + } else if ("CHANGE_DATE".equalsIgnoreCase(type)) { + BaseApiResponse createResponse = + dlService.daylightUpsertReservationNew(reservationRequestDTO, property.getDlPropertyId()); + + if (createResponse.isSuccess()) { + processResult.setSuccess(true); + processResult.setMessage("Change date success"); + } else { + processResult.setSuccess(false); + processResult.setMessage("Change date fail"); + log.warn("Change date fail"); + } + } + + return processResult; + } + + public ReservationRequestDTO buildUpsertReservationRequest(Bookings bookings) { + + String externalId = bookings.getDlExternalNo(); + + ReservationRequestDTO dto = new ReservationRequestDTO(); + + if (StringUtils.isBlank(externalId)) { + bookings.setDlExternalNo("CL-" + UUID.randomUUID().toString().replace("-", "")); + externalId = bookings.getDlExternalNo(); + bookingDao.save(bookings); + } + + CfgProperties byId = propertyDao.getById(bookings.getPropertyId()); + + BaseApiResponse> listBaseApiResponse + = dlService.daylightGetCancelReasonList(byId.getDlPropertyId()); + + List cancelReasonList = listBaseApiResponse.getData(); + String cancelReasonId = null; + + for (CancelReasonResponse c : cancelReasonList) { + if ("PLAN".equalsIgnoreCase(c.getCode())) { + cancelReasonId = c.getId(); + break; + } + } + + if (StringUtils.isBlank(cancelReasonId)) { + cancelReasonId = cancelReasonList.getFirst().getId(); + } + + dto.setCancellationReasonId(cancelReasonId); + + ReservationRequestDTO.FlowControlDTO flowControlDTO = new ReservationRequestDTO.FlowControlDTO(); + flowControlDTO.setProcessId(UUID.randomUUID().toString()); + flowControlDTO.setUpsertProfiles(true); + dto.setFlowControl(flowControlDTO); + + // externalId 已通过 dlExternalNo 字段持久化到数据库 (Bookings.dlExternalNo) + + ReservationRequestDTO.ExternalIdDTO externalIdDTO1 = new ReservationRequestDTO.ExternalIdDTO(); + ReservationRequestDTO.ExternalIdDTO externalIdDTO2 = new ReservationRequestDTO.ExternalIdDTO(); + ReservationRequestDTO.IdentityDTO identityDTO = new ReservationRequestDTO.IdentityDTO(); + + externalIdDTO1.setSystemId(daylightSystemId); + externalIdDTO1.setNumber(externalId); + + externalIdDTO2.setSystemId(daylightSystemId); + externalIdDTO2.setNumber(externalId); + + identityDTO.setExternalId(externalIdDTO1); + + dto.setIdentity(identityDTO); + dto.setExternalIds(List.of(externalIdDTO2)); + + return dto; + } + + private String buildIMComment(Bookings booking) { + + String operaComment = "GOA/TBA..APP"; + + try { + + String dateList = booking.getDateList(); + + if (dateList != null && !dateList.isEmpty()) { + JSONArray list = JSONArray.parseArray(dateList); + if (list != null && !list.isEmpty()) { + + JSONObject firstDate = list.getJSONObject(0); + Integer depositType = firstDate.getInteger("depositType"); + Integer isPost = firstDate.getInteger("isPost"); + String amendLine = getDepositComment(depositType, isPost); + + if (amendLine != null) { + operaComment += "\n" + amendLine; + } + } + } + } catch (Exception e) { + log.error("Set Opera Comment failed", e); + } + + return operaComment; + } + + private String getDepositComment(Integer depositType, Integer isPost) { + + if (depositType == null || isPost == null) { + return null; + } + + if (depositType == 0 && isPost == 1) { + return "[WAIVE DEPOSIT AND YES POST]..APP"; + } + + if (depositType == 0 && isPost == 0) { + return "[WAIVE DEPOSIT AND NO POST]..APP"; + } + + if (depositType == 1 && isPost == 1) { + return "[COLLECT DEPOSIT AND YES POST]..APP"; + } + + if (depositType == 1 && isPost == 0) { + return "[COLLECT DEPOSIT AND NO POST]..APP"; + } + + return null; + } + + private String resolveDaylightLastOperaStatus(String daylightStatus, String existingStatus) { + if (Strings.CS.equals(daylightStatus, "UNKNOWN") + && StringUtils.isNotBlank(existingStatus) + && !Strings.CS.equals(existingStatus, "UNKNOWN")) { + return existingStatus; + } + return daylightStatus; + } + + private String resolveDaylightExtendApproveStatus(boolean isWaitlist, Bookings booking) { + if (isWaitlist) { + return "W"; + } + if (booking != null && "CHECKED_IN".equalsIgnoreCase(booking.getLastOperaStatus())) { + return "N"; + } + return "PN"; + } + + private int compareBookingsViewCanonical(BookingsView a, BookingsView b) { + boolean aPlayer = StringUtils.isNotBlank(a.getPlayerId()); + boolean bPlayer = StringUtils.isNotBlank(b.getPlayerId()); + if (aPlayer != bPlayer) { + return aPlayer ? -1 : 1; + } + boolean aPn = "PN".equals(a.getApproveStatus()); + boolean bPn = "PN".equals(b.getApproveStatus()); + if (aPn != bPn) { + return aPn ? -1 : 1; + } + return Long.compare(a.getId(), b.getId()); + } + + private void foldDuplicateBookingRowsIntoPrimary(Bookings primary, Bookings duplicate) { + if (StringUtils.isBlank(primary.getConfirmationNo()) && StringUtils.isNotBlank(duplicate.getConfirmationNo())) { + primary.setConfirmationNo(duplicate.getConfirmationNo()); + } + if (StringUtils.isBlank(primary.getResvId()) && StringUtils.isNotBlank(duplicate.getResvId())) { + primary.setResvId(duplicate.getResvId()); + } + if (StringUtils.isBlank(primary.getLastOperaStatus()) && StringUtils.isNotBlank(duplicate.getLastOperaStatus())) { + primary.setLastOperaStatus(duplicate.getLastOperaStatus()); + } + if (StringUtils.isBlank(primary.getHotelCode()) && StringUtils.isNotBlank(duplicate.getHotelCode())) { + primary.setHotelCode(duplicate.getHotelCode()); + } + if (StringUtils.isBlank(primary.getMarketCode()) && StringUtils.isNotBlank(duplicate.getMarketCode())) { + primary.setMarketCode(duplicate.getMarketCode()); + } + if (StringUtils.isBlank(primary.getRatePlanCode()) && StringUtils.isNotBlank(duplicate.getRatePlanCode())) { + primary.setRatePlanCode(duplicate.getRatePlanCode()); + } + if (StringUtils.isBlank(primary.getDlSourceId()) && StringUtils.isNotBlank(duplicate.getDlSourceId())) { + primary.setDlSourceId(duplicate.getDlSourceId()); + } + if (StringUtils.isBlank(primary.getRoomTypeCode()) && StringUtils.isNotBlank(duplicate.getRoomTypeCode())) { + primary.setRoomTypeCode(duplicate.getRoomTypeCode()); + } + if (StringUtils.isBlank(primary.getChainCode()) && StringUtils.isNotBlank(duplicate.getChainCode())) { + primary.setChainCode(duplicate.getChainCode()); + } + if ((primary.getRoomTypeId() == null || primary.getRoomTypeId() <= 0) + && duplicate.getRoomTypeId() != null && duplicate.getRoomTypeId() > 0) { + primary.setRoomTypeId(duplicate.getRoomTypeId()); + } + if (StringUtils.isBlank(primary.getRoom()) && StringUtils.isNotBlank(duplicate.getRoom())) { + primary.setRoom(duplicate.getRoom()); + } + if ((primary.getRoomId() == null || primary.getRoomId() <= 0) + && duplicate.getRoomId() != null && duplicate.getRoomId() > 0) { + primary.setRoomId(duplicate.getRoomId()); + } + if (StringUtils.isBlank(primary.getPlayerId()) && StringUtils.isNotBlank(duplicate.getPlayerId())) { + primary.setPlayerId(duplicate.getPlayerId()); + } + primary.setUpdatedAt(DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss")); + } + + private void consolidateDuplicateBookingsForSameDlReservationId(List bookingViewList) { + if (bookingViewList == null || bookingViewList.size() < 2) { + return; + } + Map> byDl = new LinkedHashMap<>(); + for (BookingsView v : bookingViewList) { + if (StringUtils.isBlank(v.getDlReservationId())) { + continue; + } + String key = v.getDlReservationId().trim().toLowerCase(Locale.ROOT); + byDl.computeIfAbsent(key, k -> new ArrayList<>()).add(v); + } + Set removedIds = new HashSet<>(); + for (List group : byDl.values()) { + if (group.size() < 2) { + continue; + } + ArrayList sorted = new ArrayList<>(group); + sorted.sort(this::compareBookingsViewCanonical); + BookingsView winnerView = sorted.getFirst(); + for (int i = 1; i < sorted.size(); i++) { + BookingsView loserView = sorted.get(i); + if (removedIds.contains(winnerView.getId()) || removedIds.contains(loserView.getId())) { + continue; + } + Bookings winner = bookingDao.findById(winnerView.getId()).orElse(null); + Bookings loser = bookingDao.findById(loserView.getId()).orElse(null); + if (winner == null || loser == null) { + continue; + } + if (!Strings.CI.equals(winner.getDlReservationId(), loser.getDlReservationId())) { + continue; + } + foldDuplicateBookingRowsIntoPrimary(winner, loser); + bookingDao.save(winner); + bookingDao.delete(loser); + removedIds.add(loserView.getId()); + LogUtil.info(BookingService.class, + "[mergeDaylight] consolidated duplicate dl_reservation_id: kept booking id=" + winner.getId() + + ", removed id=" + loser.getId()); + } + } + if (!removedIds.isEmpty()) { + bookingViewList.removeIf(v -> removedIds.contains(v.getId())); + } + } + + @Transactional(rollbackFor = Exception.class) + public List mergeDaylightRecordToDatabaseInfo(List result,PlayerProfileEntry member,String userId) throws Exception { + + List dlReservationId = new ArrayList<>(); + Date now = new Date(); + for (int i = 0; i < result.size(); i++) { + BookingsView obj = result.get(i); + if( obj.getConfirmationNo()!=null && !StringUtils.isEmpty(obj.getConfirmationNo())) dlReservationId.add(obj.getDlReservationId()); + } + + List bookingView = !dlReservationId.isEmpty() ?bookingViewDao.findByDlReservationIdIn(dlReservationId): new ArrayList(); + consolidateDuplicateBookingsForSameDlReservationId(bookingView); + + List updateBookingList = new ArrayList<>(); + List cancelBookingList = new ArrayList<>(); +// List waitlistBookingList = new ArrayList(); + + for (int i = 0; i < result.size(); i++) { + BookingsView daylightBooking = new BookingsView(); + BeanUtils.copyProperties(result.get(i), daylightBooking); + + boolean bookingExist = false; + + for (int j = 0; j < bookingView.size(); j++) { + BookingsView booking = bookingView.get(j); + String status = booking.getApproveStatus(); + if(Strings.CS.contains(status, "W")) { + continue; + } + if(daylightBooking.getDlReservationId()==null) { + continue; + } + +// if (daylightBooking.getDlReservationId().equals(booking.getDlReservationId())&& +// (StringUtils.equals(daylightBooking.getHotelCode(), booking.getHotelCode())) ) { + if(daylightBooking.getDlReservationId().equals(booking.getDlReservationId())){ + bookingExist = true; + + BookingsView viewBook = bookingViewDao.findById(booking.getId()).orElse(null); + daylightBooking.setId(booking.getId()); + daylightBooking.setCreatedAt(booking.getCreatedAt()); + daylightBooking.setApproveStatus(booking.getApproveStatus()); + daylightBooking.setCreatedBy(booking.getCreatedBy()); + daylightBooking.setResvId(booking.getResvId()); + String nights = DateTimeUtil.getDiffDate(daylightBooking.getCheckinDate(), daylightBooking.getCheckoutDate(), "day"); + daylightBooking.setNumOfNight(Integer.valueOf(nights)); + daylightBooking.setPropertyName(viewBook.getPropertyName()); + daylightBooking.setSharer(booking.getSharer()); + Boolean isOperaShare = true; + daylightBooking.setShare(!isOperaShare); + + //Update from Opera DB + Bookings updateBooking = bookingDao.findById(booking.getId()).orElse(null); + if(updateBooking == null) continue; + + if(StringUtils.equals(booking.getApproveStatus(), "PN")) { + daylightBooking.setCheckinDate(booking.getCheckinDate()); + daylightBooking.setCheckoutDate(booking.getCheckoutDate()); + }else { + updateBooking.setCheckinDate(daylightBooking.getCheckinDate()); + updateBooking.setCheckoutDate(daylightBooking.getCheckoutDate()); + updateBooking.setNumOfNight(daylightBooking.getNumOfNight()); + } + updateBooking.setConfirmationNo(daylightBooking.getConfirmationNo()); + updateBooking.setHotelCode(daylightBooking.getHotelCode()); + updateBooking.setDlSourceId(daylightBooking.getDlSourceId()); + updateBooking.setDlReservationId(daylightBooking.getDlReservationId()); + + Gson gson = new Gson(); + //get room type code + CfgRoomTypes daylightRoomType = roomTypeDao.findByCodeAndCategory(daylightBooking.getRoomTypeCode(),"DAYLIGHT"); + LogUtil.info(BookingService.class,"[mergeDatabaseInfo][daylightRoomType]"+JSONObject.toJSONString(daylightRoomType)); + if(daylightRoomType!=null) { + updateBooking.setRoomTypeId(daylightRoomType.getId()); + updateBooking.setRoomTypeCode(daylightBooking.getRoomTypeCode()); + List roomroomType = roomRoomTypeDao.findByRoomTypeId(daylightRoomType.getId()); + if(roomroomType.size()>0) { + for(CfgRoomsRoomTypes r:roomroomType) { + CfgRooms room = roomDao.findById(r.getRoomId()); + if(room!=null) { + if(Long.valueOf(room.getPropertyId()).equals(updateBooking.getPropertyId())) { + updateBooking.setRoom(room.getName()); + updateBooking.setRoomId(room.getId()); + break; + } + } + } + } + } + //get Booking Type + List operaMarketCode = marketCodeDao.findByCodeAndCategory(daylightBooking.getMarketCode(), "DAYLIGHT"); + List operRateCode = rateCodeDao.findByCodeAndCategory(daylightBooking.getRatePlanCode(), "DAYLIGHT"); + if(operaMarketCode.size()>0&&operRateCode.size()>0) { + Long operaMarketCodeId = operaMarketCode.getFirst().getId(); + Long operaRateCodeId = operRateCode.getFirst().getId(); + List bookingTypeOperas = daylightViewDao.findByMarketCodeIdAndRateCodeId(operaMarketCodeId,operaRateCodeId); + if(bookingTypeOperas.size()>0) { + Long operaBookingTypeId = bookingTypeOperas.getFirst().getBookingTypeId(); + updateBooking.setBookingTypeId(operaBookingTypeId); + } + } + + if(StringUtils.equals(daylightBooking.getLastOperaStatus(), "CANCELED")) { + updateBooking.setApproveStatus("C"); + daylightBooking.setApproveStatus("C"); + }else { + if(StringUtils.equals(updateBooking.getApproveStatus(), "C")||daylightBooking.getConfirmationNo()!=null) { + updateBooking.setApproveStatus("N"); + daylightBooking.setApproveStatus("N"); + } + } + //Opera cancel booking need to increase app channel + LogUtil.info(BookingService.class,"[mergeDatabaseInfo][daylightBooking confirmationNo]"+gson.toJson(daylightBooking.getConfirmationNo())); + + LogUtil.info(BookingService.class,"[mergeDatabaseInfo][daylightBooking daylightBooking getLastOperaStatus]"+gson.toJson(StringUtils.equals(daylightBooking.getLastOperaStatus(), "CANCELED"))); + LogUtil.info(BookingService.class,"[mergeDatabaseInfo][daylightBooking getLastOperaStatus]"+gson.toJson(!StringUtils.equals(updateBooking.getLastOperaStatus(), "CANCELED"))); + LogUtil.info(BookingService.class,"[mergeDatabaseInfo][booking is decrease app channel]"+gson.toJson( + StringUtils.equals(daylightBooking.getLastOperaStatus(), "CANCELED")&& + !StringUtils.equals(updateBooking.getLastOperaStatus(), "CANCELED"))); + if(StringUtils.equals(daylightBooking.getLastOperaStatus(), "CANCELED")&& + !StringUtils.equals(updateBooking.getLastOperaStatus(), "CANCELED")) { + LogUtil.info(BookingService.class,"[mergeDatabaseInfo][viewBook.getRoomId()]"+gson.toJson(viewBook.getRoomId())); + LogUtil.info(BookingService.class,"[mergeDatabaseInfo][viewBook.getBlockId()]"+gson.toJson(viewBook.getBlockId())); + if(viewBook.getRoomId()!=null&&viewBook.getBlockId()!=null) { + //Increase app channel + cancelBookingList.add(viewBook); + } + + } + updateBooking.setLastOperaStatus(daylightBooking.getLastOperaStatus()); + + //get player info + if(updateBooking.getMember()==null||StringUtils.isEmpty(updateBooking.getMember())) { + if(!StringUtils.isEmpty(updateBooking.getPlayerId())) { + BaseApiResponse serviceResult = playerService.findWebPlayerProfileByPlayerId(updateBooking.getPlayerId()); + if(serviceResult.isSuccess()) { + PlayerProfileEntry profile = serviceResult.getData(); + updateBooking.setMemberLastName(profile.getName()); + updateBooking.setMemberTitle(profile.getSalutation()); + updateBooking.setMember(JSONObject.toJSONString(profile)); + } + } + } + //get user info + boolean getUser = false; + String booker = StringUtils.trim(updateBooking.getBooker()); + if(booker==null||StringUtils.isEmpty(booker)) getUser=true; + if(!StringUtils.equals(updateBooking.getCreatedBy(), daylightBooking.getCreatedBy())) { + updateBooking.setCreatedBy(daylightBooking.getCreatedBy()); + getUser=true; + } + if(getUser) { + if(!StringUtils.isEmpty(updateBooking.getCreatedBy())) { + BaseApiResponse userInfoRes = mgmUserService.findUserInfoByUserId(updateBooking.getCreatedBy()); + if(userInfoRes.isSuccess()) { + UserInfoApiRecord userInfo = (UserInfoApiRecord)userInfoRes.getData(); + updateBooking.setBooker(userInfo.getUserName()); + updateBooking.setCreatedByName(userInfo.getUserName()); + } + } + } + + updateBookingList.add(updateBooking); + + int expMin = 20000; +// AppSetting approvalExpMin = appSettingRepository.getByKeys(SettingConstants.APPROVAL_EXPIRE_MINUTES); +// if (approvalExpMin != null && StringUtils.isNotBlank(approvalExpMin.getKeyValues())) { +// expMin = Integer.valueOf(approvalExpMin.getKeyValues()); +// } + expMin = expMin * -1; + Date dtNow = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + dtNow = DateTimeUtil.addMin(dtNow, expMin); + + Long revisionOf = (long) 0; + for (int k = 0; k < bookingView.size(); k++) { + BookingsView bookingPending = bookingView.get(k); + + if (booking.getId().equals(bookingPending.getRevisionOf()) + && (StringUtils.equals(bookingPending.getApproveStatus(), "PN")||StringUtils.equals(bookingPending.getApproveStatus(), "W")) + && bookingPending.getCreatedAt().getTime() >= dtNow.getTime()) { + if (bookingPending.getId() > revisionOf) { + daylightBooking.setPendingRevisionId(bookingPending.getId()); + } + revisionOf = bookingPending.getId(); + } + } + } + } + + //show opera booking in records + if (bookingExist == false) { + daylightBooking = this.insertDaylightBooking(daylightBooking,member,userId); + } + result.set(i, daylightBooking); + } + + if (updateBookingList.size() > 0) { + bookingDao.saveAll(updateBookingList); + } + +// if (waitlistBookingList.size() > 0) { +// bookingDao.saveAll(waitlistBookingList); +// } + + //计算cancel booking + if(cancelBookingList.size()>0) { + for(BookingsView cb:cancelBookingList) { + this.processAllotment(cb.getRoomId(), cb.getCheckinDate(), cb.getCheckoutDate(), cb.getPropertyId(), cb.getBlockId()); + } + } + + // hide booking with pending revisions, instead, shows the pending version or waitlist booking + for (int j = result.size() - 1; j >= 0; j--) { + if (result.get(j).getPendingRevisionId() != null) { + result.remove(j); + } + } + + return result; + } + + public BaseApiResponse> editBooking(BookingDto param, HttpServletRequest request, PlayerProfileEntry player, String category) throws Exception { + if ("DAYLIGHT".equalsIgnoreCase(category)) { + return editDaylightBooking(param, request, player); + } + + if ("OPERA".equalsIgnoreCase(category) || "OTHER".equalsIgnoreCase(category)) { + return editOperaOtherBooking(param, request, player); + } + + BaseApiResponse> response = new BaseApiResponse<>(); + + response.setSuccess(false); + response.setMessage("Edit booking fail, unknown category: " + category); + log.warn("Edit booking fail, unknown category: {}", category); + + return response; + } + + private BaseApiResponse> editOperaOtherBooking(BookingDto param, HttpServletRequest request, PlayerProfileEntry player) { + BaseApiResponse> processResult = new BaseApiResponse<>(); + Date createDate = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + + Long bookId = param.getId(); + String sharer = param.getSharer(); + String remark = param.getRemark(); + Long segmentId = param.getSegmentId(); + List dateList = param.getDateList(); + BookingDateEntry dateItem = dateList.getFirst(); + List dateArr = dateItem.getDate(); + List extendDateList = param.getExtendDate(); + BookingDateEntry extendDate = extendDateList.getFirst(); + + boolean isWaitlist = extendDate.getStatus() != null && extendDate.getStatus() == 1; + boolean submitTag = extendDate.isSubmit(); + String bookingStatus = extendDate.getBookingStatus(); + Date originCheckinDate = DateTimeUtil.getDateFromString( + String.valueOf(dateArr.getFirst()), "yyyy-MM-dd"); + Date checkinDate = param.getCheckinDate(); + Date checkoutDate = param.getCheckoutDate(); + String numOfNight = DateTimeUtil.getDiffDate(checkinDate, checkoutDate, "day"); + + BookingUserEntry user = param.getUser(); + String userId = user.getUserId(); + String userName = user.getUserName(); + + Bookings originalBooking = bookingDao.findById(bookId).orElse(null); + if (originalBooking == null) { + processResult.setSuccess(false); + processResult.setMessage("Booking not found."); + return processResult; + } + + Bookings booking; + if (isWaitlist) { + booking = new Bookings(); + BeanUtils.copyProperties(originalBooking, booking, "id"); + booking.setId(null); + } else { + booking = originalBooking; + } + + boolean isShareBooking = !StringUtils.isEmpty(originalBooking.getSharer()) + && !Strings.CS.equals("[]", booking.getSharer()); + if (!isShareBooking) { + boolean isOperaShare = this.checkRoomNo(originalBooking.getId(), + DateTimeUtil.getDateByFormat( + booking.getCheckinDate(), "yyyy-MM-dd"), + DateTimeUtil.getDateByFormat( + booking.getCheckoutDate(), "yyyy-MM-dd")); + + isShareBooking = !isOperaShare; + } + + String oldStatus = + EumnApprovalStatus.getApprovalStatusByDBValue( + booking.getApproveStatus()); + + booking.setRevisionOf(bookId); + booking.setCheckinDate(originCheckinDate); + booking.setCheckoutDate(checkoutDate); + booking.setApproveStatus(isWaitlist ? "W" : "PN"); + booking.setRemark(remark); + booking.setBookType("1"); + booking.setNumOfNight(Integer.valueOf(numOfNight)); + booking.setSharer(sharer); + booking.setDateList(JSONArray.toJSONString(extendDateList)); + booking.setUpdatedAt(createDate); + booking.setUpdatedBy(userId); + booking.setCreatedAt(createDate); + + if (isWaitlist) { + booking.setCheckinDate(checkinDate); + booking.setRevisionOf(null); + } + + // 判断 Edit 的日期是否超过 CMS 设置 + CfgSettings maxBookingStayDays = + settingService.getSettingByKey(SysConstants.MAX_BOOKING_STAY_DAYS); + + if (maxBookingStayDays != null + && booking.getNumOfNight() + > Integer.parseInt(maxBookingStayDays.getKeyValues())) { + + processResult.setSuccess(false); + processResult.setMessage("Exceeded Maximum Booking Stay Days"); + return processResult; + } + + List resultBookings = new ArrayList<>(); + + BookingsView originBook = bookingViewDao.findById(bookId).orElse(null); + + if (originBook == null) { + processResult.setSuccess(false); + processResult.setMessage("Original booking view not found."); + return processResult; + } + + originBook.setMemberTier(player.getTierName()); + + JSONArray dynList = !StringUtils.isEmpty(booking.getSharer()) + && !Strings.CS.equals("[]", booking.getSharer()) + ? JSONArray.parseArray(booking.getSharer()) + : new JSONArray(); + + StringBuilder sharerString = new StringBuilder(); + + if (!dynList.isEmpty()) { + for (int a = 0; a < dynList.size(); a++) { + Gson gson = new Gson(); + JSONObject shareObj = (JSONObject) dynList.get(a); + + String sharePlayerId = shareObj.getString("playerId"); + String shareName = shareObj.getString("name"); + + LogUtil.info(BookingService.class, "[editBooking] sharePlayerId " + gson.toJson(sharePlayerId)); + + LogUtil.info(BookingService.class, "[editBooking] shareName " + gson.toJson(shareName)); + + if (!StringUtils.isEmpty(sharePlayerId)) { + sharerString.append(sharePlayerId).append(" ").append(shareName).append(" "); + } else if (!StringUtils.isEmpty(shareName)) { + sharerString.append(shareName).append(" "); + } + } + } + + originBook.setSharerName(sharerString.toString()); + originBook.setMemberLastName(player.getName()); + booking.setMemberLastName(player.getName()); + + if (submitTag && !bookingStatus.equals("PN")) { + + // Extend booking send email + if (!isWaitlist) { + + if (segmentId != null) { + // NON MGM Booking + Bookings oBook = editOtherBooking(bookId, checkinDate, checkoutDate, segmentId); + resultBookings.add(oBook); + processResult.setSuccess(true); + processResult.setData(resultBookings); + } else { + // MGM Booking + Bookings emailBook = booking; + Email email = new Email(); + + email.setBookId(originBook.getId()); + email.setCreatedAt(createDate); + email.setCreatedBy(userId); + + CfgSettings emailAddress = settingService.getSettingByKey(SysConstants.MGM_EMAIL_ADDRESS); + + email = SendEmail.sendExtendEmail(emailBook, originBook, email, userId, userName, emailAddress.getKeyValues()); + + if (email.getStatus() == 1) { + processResult.setSuccess(true); + processResult.setCode("EMAIL"); + } else { + processResult.setSuccess(false); + processResult.setMessage("Send Email Failed."); + } + + processResult.setSuccess(true); + + emailDao.save(email); + processResult.setData(resultBookings); + } + + } else { + booking.setWaitlistId(originBook.getId()); + booking.setOtherFollowUpStatusId(2L); + booking.setCheckinDate( + originBook.getCheckoutDate() + ); + booking.setCheckoutDate( + DateTimeUtil.getDateFromString(param.getChangeCheckoutDate(),"yyyy-MM-dd")); + + Bookings newBooking = bookingDao.save(booking); + + ArrayList booksList = new ArrayList<>(); + booksList.add(newBooking); + + resultBookings.add(newBooking); + + sysLogBookingService.saveLogBooking(booksList, request, "", "", "Create Extension Booking", ""); + + processResult.setSuccess(true); + processResult.setData(resultBookings); + } + } + + return processResult; + } + + + private BaseApiResponse> editDaylightBooking(BookingDto param, HttpServletRequest request, PlayerProfileEntry player) throws Exception { + BaseApiResponse> processResult = new BaseApiResponse<>(); + Date createDate = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + Long bookId = param.getId(); + String sharer = param.getSharer(); + String remark = param.getRemark(); + List dateList = param.getDateList(); + BookingDateEntry dateItem = dateList.getFirst(); + List dateArr = dateItem.getDate(); + List extendDateList = param.getExtendDate(); + BookingDateEntry extendDate = extendDateList.getFirst(); + boolean isWaitlist = extendDate.getStatus()!=null && extendDate.getStatus()==1; + boolean submitTag = extendDate.isSubmit(); + String bookingStatus = extendDate.getBookingStatus(); + Date originCheckinDate = DateTimeUtil.getDateFromString(String.valueOf(dateArr.getFirst()), "yyyy-MM-dd");; + Date checkinDate = param.getCheckinDate(); + Date checkoutDate = param.getCheckoutDate(); + String numOfNight = DateTimeUtil.getDiffDate(checkinDate, checkoutDate, "day"); + BookingUserEntry user = param.getUser(); + String userId = user.getUserId(); + String userName = user.getUserName(); + Bookings originalBooking = bookingDao.findById(bookId).orElse(null); + if (originalBooking == null) { + processResult.setSuccess(false); + processResult.setMessage("Booking not found."); + return processResult; + } + + Bookings booking; + if (isWaitlist) { + booking = new Bookings(); + BeanUtils.copyProperties(originalBooking, booking, "id"); + booking.setId(null); + } else { + booking = originalBooking; + } + + booking.setCheckinDate(originCheckinDate); + booking.setCheckoutDate(checkoutDate); + booking.setApproveStatus(resolveDaylightExtendApproveStatus(isWaitlist, booking)); + booking.setRemark(remark); + booking.setBookType("1"); + booking.setNumOfNight(Integer.valueOf(numOfNight)); + booking.setSharer(sharer); + booking.setDateList(JSONArray.toJSONString(extendDateList)); + booking.setUpdatedAt(createDate); + booking.setUpdatedBy(userId); + booking.setCreatedAt(createDate); + if(isWaitlist) { + booking.setCheckinDate(checkinDate); + booking.setRevisionOf(null); + } + //判断Edit的日期是否超过CMS设置 + CfgSettings maxBookingStayDays = settingService.getSettingByKey(SysConstants.MAX_BOOKING_STAY_DAYS); + + if(maxBookingStayDays != null && booking.getNumOfNight()>Integer.parseInt(maxBookingStayDays.getKeyValues())) { + processResult.setSuccess(false); + processResult.setMessage("Exceeded Maximum Booking Stay Days"); + return processResult; + } + + List resultBookings = new ArrayList<>(); + + BookingsView originBook = bookingViewDao.findById(bookId).orElse(null); + assert originBook != null; + originBook.setMemberTier(player.getTierName()); + JSONArray dynList = !StringUtils.isEmpty(booking.getSharer())&&!Strings.CS.equals("[]", booking.getSharer())? + JSONArray.parseArray(booking.getSharer()) :new JSONArray(); + StringBuilder sharerString = new StringBuilder(); + if (!dynList.isEmpty()) { + for (int a = 0; a < dynList.size(); a++) { + Gson gson = new Gson(); + JSONObject shareObj = (JSONObject) dynList.get(a); + String sharePlayerId = shareObj.getString("playerId"); + String shareName = shareObj.getString("name"); + LogUtil.info(BookingService.class, + "[editBooking] sharePlayerId " + gson.toJson(sharePlayerId)); + LogUtil.info(BookingService.class, + "[editBooking] shareName " + gson.toJson(shareName)); + if(!StringUtils.isEmpty(sharePlayerId)) { + sharerString.append(sharePlayerId).append(" ").append(shareName).append(" "); + }else if(!StringUtils.isEmpty(shareName)) { + sharerString.append(shareName).append(" "); + } + } + } + originBook.setSharerName(sharerString.toString()); + originBook.setMemberLastName(player.getName()); + booking.setMemberLastName(player.getName()); + + if(submitTag && !bookingStatus.equals("PN") && !isWaitlist) { + + TodoChangeDateRequest changeRequest = bookingMapper.bookingDtoToChangeRequest(param); + + BaseApiResponse> result = this.daylightReservationChangeDate(changeRequest, player, true); + if (result.isSuccess()) { + processResult.setSuccess(true); + processResult.setData(resultBookings); + } else { + processResult.setSuccess(false); + processResult.setCode(result.getMessage()); + } + } else if (isWaitlist) { + booking.setWaitlistId(originBook.getId()); + booking.setOtherFollowUpStatusId(2L); + booking.setCheckinDate(originBook.getCheckoutDate()); + booking.setDlReservationId(null); + booking.setDlExternalNo(null); + booking.setCheckoutDate( + DateTimeUtil.getDateFromString(param.getChangeCheckoutDate(),"yyyy-MM-dd")); + Bookings newBooking = bookingDao.save(booking); + + ArrayList booksList = new ArrayList<>(); + booksList.add(newBooking); + resultBookings.add(newBooking); + sysLogBookingService.saveLogBooking(booksList, request, "", "", "Create Extension Booking",""); + processResult.setSuccess(true); + processResult.setData(resultBookings); + } + + return processResult; + } + + public BaseApiResponse> daylightReservationChangeDate(TodoChangeDateRequest param, PlayerProfileEntry player, boolean isExtend) throws Exception { + BaseApiResponse> processResult = new BaseApiResponse<>(); + Date createDate = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + Long bookId = param.getId(); + String sharer = param.getSharer(); + String remark = param.getRemark(); + List bookingDateList = param.getDateList(); + BookingDateEntry dateEntry = bookingDateList.getFirst(); + List dateArr = dateEntry.getDate(); + List extendDateList = null; + Date originCheckinDate = DateTimeUtil.getDateFromString(dateArr.getFirst(), "yyyy-MM-dd"); + Date checkinDate; + Date checkoutDate; + + Bookings booking = bookingDao.findById(bookId).orElse(null); + + //在ExtendBooking中 有checkinDate 和 checkInDate checkInDate是ExtendBooking的checkInDate checkoutDate同理 + if (isExtend) { + extendDateList = param.getExtendDate(); + BookingDateEntry extDateEntry = extendDateList.getFirst(); + boolean isWaitlist = (extDateEntry.getStatus() != null && extDateEntry.getStatus() == 1); + booking.setApproveStatus(resolveDaylightExtendApproveStatus(isWaitlist, booking)); + + List extendDateListTemp = extDateEntry.getDate(); + + String s = extendDateListTemp.getLast(); + + checkinDate = param.getCheckinDate(); + checkoutDate = DateTimeUtil.getDateFromString(s, "yyyy-MM-dd"); + + String newComment = buildDaylightExtendComment(booking, checkoutDate, booking.getCreatedBy()); + + booking.setOperaComment(newComment); + + CfgProperties pp = propertyDao.findById(String.valueOf(booking.getPropertyId())).orElse(null); + + BaseApiResponse response = + dlService.daylightGetNoteListById(pp.getDlPropertyId(), booking.getDlReservationId()); + + ReservationNoteResponse noteData = response.getData(); + + dlService.daylightUpdateReservationNote( + pp.getDlPropertyId(), + booking.getDlReservationId(), + noteData.getNoteId(), + newComment, + noteData.getVersion()); + + if(isWaitlist) { + booking.setCheckinDate(checkinDate); + booking.setRevisionOf(null); + } + }else{ + checkinDate = param.getCheckinDate(); + checkoutDate = param.getCheckoutDate(); + } + String checkinDateStr = DateTimeUtil.getDateByFormat(checkinDate, "yyyy-MM-dd"); + String checkoutDateStr = DateTimeUtil.getDateByFormat(checkoutDate, "yyyy-MM-dd"); + String numOfNight = DateTimeUtil.getDiffDate(checkinDate, checkoutDate, "day"); + + boolean isShareBooking = !StringUtils.isEmpty(booking.getSharer()) && !"[]".equals(booking.getSharer()); + if (!isShareBooking) { + boolean isOperaShare = true; + isOperaShare = this.checkRoomNo(booking.getId(), + DateTimeUtil.getDateByFormat(booking.getCheckinDate(), "yyyy-MM-dd"), + DateTimeUtil.getDateByFormat(booking.getCheckoutDate(), "yyyy-MM-dd")); + isShareBooking = !isOperaShare; + } + booking.setId(bookId); +// booking.setRevisionOf(bookId); + booking.setCheckinDate(originCheckinDate); + booking.setCheckoutDate(checkoutDate); + booking.setRemark(remark); + booking.setBookType("1"); + booking.setNumOfNight(Integer.valueOf(numOfNight)); + booking.setSharer(sharer); + booking.setUpdatedAt(createDate); + booking.setUpdatedBy(param.getUserId()); + booking.setCreatedAt(createDate); + + if (isExtend) { + List tempDateList = extendDateList.getFirst().getDate(); + String extendCheckOutDateStr = tempDateList.getLast(); + Date extendCheckOutDate = DateTimeUtil.getDateFromString(extendCheckOutDateStr, "yyyy-MM-dd"); + + extendDateList = this.buildDefaultDateList(checkinDate, extendCheckOutDate); + booking.setDateList(JSONArray.toJSONString(extendDateList)); + } else { + List bookingDateEntries = this.buildDefaultDateList(checkinDate, checkoutDate); + booking.setDateList(JSONArray.toJSONString(bookingDateEntries)); + } + + //判断Edit的日期是否超过CMS设置 + CfgSettings maxBookingStayDays = settingService.getSettingByKey(SysConstants.MAX_BOOKING_STAY_DAYS); + + if (maxBookingStayDays != null && booking.getNumOfNight() > Integer.parseInt(maxBookingStayDays.getKeyValues())) { + processResult.setSuccess(false); + processResult.setMessage("Exceeded Maximum Booking Stay Days"); + return processResult; + } + + List resultBookings = new ArrayList<>(); + + BookingsView originBook = bookingViewDao.findById(bookId).orElse(null); + originBook.setMemberTier(player.getTierName()); + JSONArray dynList = !StringUtils.isEmpty(booking.getSharer()) && !Strings.CS.equals("[]", booking.getSharer()) ? + JSONArray.parseArray(booking.getSharer()) : new JSONArray(); + StringBuilder sharerString = new StringBuilder(); + if (!dynList.isEmpty()) { + for (int a = 0; a < dynList.size(); a++) { + JSONObject shareObj = dynList.getJSONObject(a); + String sharePlayerId = shareObj.getString("playerId"); + String shareName = shareObj.getString("name"); + LogUtil.info(BookingService.class, "[editBooking] sharePlayerId=" + sharePlayerId); + LogUtil.info(BookingService.class, "[editBooking] shareName=" + shareName); + if (!StringUtils.isEmpty(sharePlayerId)) { + sharerString.append(sharePlayerId).append(" ").append(shareName).append(" "); + } else if (!StringUtils.isEmpty(shareName)) { + sharerString.append(shareName).append(" "); + } + } + } + originBook.setSharerName(sharerString.toString()); + originBook.setMemberLastName(player.getName()); + booking.setMemberLastName(player.getName()); + + booking.setWaitlistId(originBook.getId()); + Bookings newBooking = bookingDao.save(booking); + resultBookings.add(newBooking); + + CfgProperties property = propertyDao.getById(booking.getPropertyId()); + + BaseApiResponse result = + dlService.daylightChangeReservationByDlId(bookId, checkinDateStr, checkoutDateStr, property.getDlPropertyId()); + +// BaseApiResponse> result = this.callDaylightUpsertReservation(newBooking, "CHANGE_DATE"); + +// Thread.sleep(2000L); +// if (booking.getDlBlockId() != null) +// dlService.daylightReservationSetBlock(booking.getDlReservationId(), property.getDlPropertyId(), booking.getDlBlockId()); + + // TODO Need to create a new comp rule when extend the booking by Mauve 20260827 + List daylightViewList = daylightViewDao.findBySectionPropertyBookingTypeRoomType( + booking.getSectionId(), + booking.getPropertyId(), + booking.getBookingTypeId(), + booking.getRoomTypeId() + ); + CfgDaylightView daylightViewRoomOnly = null; + if(daylightViewList!=null){ + for (CfgDaylightView d : daylightViewList) { + if (d.getCompRuleCategory() == 1) { + daylightViewRoomOnly = d; + } + } + } + + DaylightReservationResponse daylightReservationByDlId = + dlService.getDaylightReservationByDlId(booking.getDlReservationId(), property.getDlPropertyId()); + + BaseApiResponse compRuleListResponse = dlService.daylightGetCompRulesByAccount(property.getDlPropertyId(),daylightReservationByDlId.getAccountId()); + if(compRuleListResponse.isSuccess()&&daylightViewRoomOnly!=null){ + JSONArray compRuleList = compRuleListResponse.getData(); + boolean hasSameUser = false; + for (int i = 0; i < compRuleList.size(); i++) { + JSONObject one = compRuleList.getJSONObject(i); + String approverId = one.getString("approverId"); + if(Strings.CS.equals(approverId,param.getUserId()) + || Strings.CS.equals(approverId,daylightViewRoomOnly.getApprover()) ){ + hasSameUser = true; + } + } + if(!hasSameUser) dlService.createDaylightNewRoomOnlyCompRule( + daylightReservationByDlId.getAccountId(), + daylightReservationByDlId.getProfileId(), + property.getDlPropertyId(), + param.getUserId(), + checkinDateStr, + checkoutDateStr, + daylightViewRoomOnly + ); + } + + + bookingDao.save(booking); + + if (result.isSuccess()) { + processResult.setSuccess(true); + processResult.setData(resultBookings); + } else { + processResult.setSuccess(false); + processResult.setMessage(result.getMessage()); + } + + return processResult; + } + + private List buildDefaultDateList(Date checkinDate, Date checkoutDate) { + int numOfNight = Integer.parseInt(DateTimeUtil.getDiffDate(checkinDate, checkoutDate, "day")); + List dates = new ArrayList<>(); + for (int j = 0; j < numOfNight + 1; j++) { + dates.add(DateTimeUtil.getDateByFormat(DateTimeUtil.addDay(checkinDate, j), "yyyy-MM-dd")); + } + BookingDateEntry dateEntry = new BookingDateEntry(); + dateEntry.setBookingStatus(""); + dateEntry.setChecked(false); + dateEntry.setDate(dates); + dateEntry.setNumOfNight(numOfNight); + dateEntry.setNumOfRoom(1); + dateEntry.setRemark(""); + dateEntry.setStatus(0); + dateEntry.setSubmit(true); + List dateList = new ArrayList<>(); + dateList.add(dateEntry); + return dateList; + } + + private Bookings editOtherBooking(Long bookId,Date checkinDate,Date checkoutDate,Long segmentId) { + Bookings oBooking = bookingDao.findById(bookId).orElse(null); + oBooking.setRequestedCoDate(checkoutDate); + oBooking.setOtherFollowUpStatusId(Long.valueOf("2")); + bookingDao.save(oBooking); + otherBookingService.processOtherAllotment(oBooking.getRoomId(), checkoutDate, + checkinDate, oBooking.getPropertyId(), oBooking.getSegmentId()); + return oBooking; + } + + public BaseApiResponse cancelWaitlistBooking(BookingDto param,HttpServletRequest request) { + BaseApiResponse processResult= new BaseApiResponse<>(); + Date createDate = new Date(); + Bookings booking = new Bookings(); + Long bookId = param.getId(); + String userId = param.getUserId(); + ArrayList booksList = new ArrayList<>(); + booking = bookingDao.findById(bookId).orElse(null); + String status = booking.getApproveStatus(); + + booking.setApproveStatus("WC"); + booking.setUpdatedAt(createDate); + booking.setUpdatedBy(userId); + + bookingDao.save(booking); + + processResult.setSuccess(true); + processResult.setData(booking); + booksList.add(booking); + String oldStatus = EumnApprovalStatus.getApprovalStatusByDBValue(status); + String newStatus = EumnApprovalStatus.getApprovalStatusByDBValue("WC"); + sysLogBookingService.saveLogBooking(booksList, request,oldStatus,newStatus,"Cancel Booking",""); + + return processResult; + } + + public BaseApiResponse approveWaitlistBooking(BookingDto param,HttpServletRequest request) { + BaseApiResponse processResult= new BaseApiResponse<>(); + Date createDate = new Date(); + Long bookId = param.getId(); + String userId = param.getUserId(); + String userName = param.getUserName(); + String status = param.getStatus(); + + Bookings booking = bookingDao.findById(bookId).orElse(null); + + booking.setApproveStatus(status); + booking.setUpdatedAt(createDate); + booking.setUpdatedBy(userId); + booking.setApprovedBy(userName); + booking.setApprovedAt(createDate); + + bookingDao.save(booking); + + processResult.setSuccess(true); + processResult.setData(booking); + + return processResult; + } + + public List mergeOperaRecordToDatabaseInfo(List result, PlayerProfileEntry member, String userId) throws Exception { + List confirmationNo = new ArrayList<>(); + Date now = new Date(); + for (int i = 0; i < result.size(); i++) { + BookingsView obj = result.get(i); + if( obj.getConfirmationNo()!=null && !StringUtils.isEmpty(obj.getConfirmationNo())) confirmationNo.add(obj.getConfirmationNo()); + } + + List bookingView = !confirmationNo.isEmpty() ?bookingViewDao.findByConfirmationNoIn(confirmationNo): new ArrayList(); + + List updateBookingList = new ArrayList<>(); + List cancelBookingList = new ArrayList<>(); +// List waitlistBookingList = new ArrayList(); + + for (int i = 0; i < result.size(); i++) { + BookingsView operaBooking = new BookingsView(); + BeanUtils.copyProperties(result.get(i), operaBooking); + + boolean bookingExist = false; + + for (int j = 0; j < bookingView.size(); j++) { + BookingsView booking = bookingView.get(j); + String status = booking.getApproveStatus(); + if(Strings.CS.contains(status, "W")) { + continue; + } + if(operaBooking.getConfirmationNo()==null) { + continue; + } + + if (operaBooking.getConfirmationNo().equals(booking.getConfirmationNo())&& + (Strings.CS.equals(operaBooking.getHotelCode(), booking.getHotelCode())) ) { + bookingExist = true; + + BookingsView viewBook = bookingViewDao.findById(booking.getId()).orElse(null); + operaBooking.setId(booking.getId()); + operaBooking.setCreatedAt(booking.getCreatedAt()); + operaBooking.setApproveStatus(booking.getApproveStatus()); + operaBooking.setCreatedBy(booking.getCreatedBy()); + operaBooking.setResvId(booking.getResvId()); + String nights = DateTimeUtil.getDiffDate(operaBooking.getCheckinDate(), operaBooking.getCheckoutDate(), "day"); + operaBooking.setNumOfNight(Integer.valueOf(nights)); + operaBooking.setPropertyName(viewBook.getPropertyName()); + operaBooking.setSharer(booking.getSharer()); + boolean isOperaShare = true; + isOperaShare = this.checkRoomNo(booking.getId(), + DateTimeUtil.getDateByFormat(booking.getCheckinDate(), "yyyy-MM-dd") , + DateTimeUtil.getDateByFormat(booking.getCheckoutDate(), "yyyy-MM-dd")); + operaBooking.setShare(!isOperaShare); + + //Update from Opera DB + Bookings updateBooking = bookingDao.findById(booking.getId()).orElse(null); + if(updateBooking == null) continue; + + if(Strings.CS.equals(booking.getApproveStatus(), "PN")) { + operaBooking.setCheckinDate(booking.getCheckinDate()); + operaBooking.setCheckoutDate(booking.getCheckoutDate()); + }else { +// if(operaBooking.getCheckoutDate()!=updateBooking.getCheckoutDate()) { +// List getWaitlistBooking = bookingDao.findByWaitlistIdAndCheckoutDateAndApproveStatus(updateBooking.getId(), +// operaBooking.getCheckoutDate(),"WA"); +// if(getWaitlistBooking.size()>0) { +// for(Bookings waitBook:getWaitlistBooking) { +// waitBook.setApproveStatus("WF"); +// waitlistBookingList.add(waitBook); +// } +// } +// } + updateBooking.setCheckinDate(operaBooking.getCheckinDate()); + updateBooking.setCheckoutDate(operaBooking.getCheckoutDate()); + updateBooking.setNumOfNight(operaBooking.getNumOfNight()); + } + + updateBooking.setRatePlanCode(operaBooking.getRatePlanCode()); + updateBooking.setHotelCode(operaBooking.getHotelCode()); + updateBooking.setMarketCode(operaBooking.getMarketCode()); + + Gson gson = new Gson(); + + if(operaBooking.getBlockId()!=null) { + updateBooking.setBlockId(operaBooking.getBlockId()); + List blockCodes = blockCodeDao.findByCode(operaBooking.getHotelCode()); + if(!blockCodes.isEmpty()) { + Long operaBlockId = blockCodes.getFirst().getBlockId(); + if(operaBlockId!=null) { + updateBooking.setBlockId(operaBlockId); + } + } + } + //get room type code + CfgRoomTypes operRoomType = roomTypeDao.findByCodeAndCategory(operaBooking.getRoomTypeCode(),operaBooking.getPropertyCategory()); +// LogUtil.info(BookingService.class,"[mergeDatabaseInfo][operRoomType]"+gson.toJson(operRoomType)); + if(operRoomType!=null) { + updateBooking.setRoomTypeId(operRoomType.getId()); + updateBooking.setRoomTypeCode(operaBooking.getRoomTypeCode()); + List roomroomType = roomRoomTypeDao.findByRoomTypeId(operRoomType.getId()); + if(!roomroomType.isEmpty()) { + for(CfgRoomsRoomTypes r:roomroomType) { + CfgRooms room = roomDao.findById(r.getRoomId()); + if(room!=null) { + if(Long.valueOf(room.getPropertyId()).equals(updateBooking.getPropertyId())) { + updateBooking.setRoom(room.getName()); + updateBooking.setRoomId(room.getId()); + break; + } + } + } + } + } + //get Booking Type + List operaMarketCode = marketCodeDao.findByCodeAndCategory(operaBooking.getMarketCode(), "OPERA"); + List operRateCode = rateCodeDao.findByCodeAndCategory(operaBooking.getRatePlanCode(), "OPERA"); + if(!operaMarketCode.isEmpty() && !operRateCode.isEmpty()) { + Long operaMarketCodeId = operaMarketCode.getFirst().getId(); + Long operaRateCodeId = operRateCode.getFirst().getId(); + List bookingTypeOperas = operaViewDao.findByMarketCodeIdAndRateCodeId(operaMarketCodeId,operaRateCodeId); + if(!bookingTypeOperas.isEmpty()) { + Long operaBookingTypeId = bookingTypeOperas.getFirst().getBookingTypeId(); + updateBooking.setBookingTypeId(operaBookingTypeId); + } + } + + if(Strings.CS.equals(operaBooking.getLastOperaStatus(), "CANCELED")) { + updateBooking.setApproveStatus("C"); + operaBooking.setApproveStatus("C"); + }else { + if(Strings.CS.equals(updateBooking.getApproveStatus(), "C")) { + updateBooking.setApproveStatus("N"); + operaBooking.setApproveStatus("N"); + } + } + //Opera cancel booking need to increase app channel + LogUtil.info(BookingService.class,"[mergeDatabaseInfo][operaBooking confirmationNo]"+gson.toJson(operaBooking.getConfirmationNo())); + + LogUtil.info(BookingService.class,"[mergeDatabaseInfo][operaBooking operaBooking getLastOperaStatus]"+gson.toJson(Strings.CS.equals(operaBooking.getLastOperaStatus(), "CANCELED"))); + LogUtil.info(BookingService.class,"[mergeDatabaseInfo][operaBooking getLastOperaStatus]"+gson.toJson(!Strings.CS.equals(updateBooking.getLastOperaStatus(), "CANCELED"))); + LogUtil.info(BookingService.class,"[mergeDatabaseInfo][booking is decrease app channel]"+gson.toJson( + Strings.CS.equals(operaBooking.getLastOperaStatus(), "CANCELED")&& + !Strings.CS.equals(updateBooking.getLastOperaStatus(), "CANCELED"))); + if(Strings.CS.equals(operaBooking.getLastOperaStatus(), "CANCELED")&& + !Strings.CS.equals(updateBooking.getLastOperaStatus(), "CANCELED")) { + LogUtil.info(BookingService.class,"[mergeDatabaseInfo][viewBook.getRoomId()]"+gson.toJson(viewBook.getRoomId())); + LogUtil.info(BookingService.class,"[mergeDatabaseInfo][viewBook.getBlockId()]"+gson.toJson(viewBook.getBlockId())); + if(viewBook.getRoomId()!=null&&viewBook.getBlockId()!=null) { + //Increase app channel + cancelBookingList.add(viewBook); + } + + } + updateBooking.setLastOperaStatus(operaBooking.getLastOperaStatus()); + + //get player info + if(updateBooking.getMember()==null||StringUtils.isEmpty(updateBooking.getMember())) { + if(!StringUtils.isEmpty(updateBooking.getPlayerId())) { + BaseApiResponse serviceResult = playerService.findWebPlayerProfileByPlayerId(updateBooking.getPlayerId()); + if(serviceResult.isSuccess()) { + PlayerProfileEntry profile = serviceResult.getData(); + updateBooking.setMemberLastName(profile.getName()); + updateBooking.setMemberTitle(profile.getSalutation()); + updateBooking.setMember(JSONObject.toJSONString(profile)); + } + } + } + //get user info + boolean getUser = false; + String booker = StringUtils.trim(updateBooking.getBooker()); + if(booker==null||StringUtils.isEmpty(booker)) getUser=true; + if(!Strings.CS.equals(updateBooking.getCreatedBy(), operaBooking.getCreatedBy())) { + updateBooking.setCreatedBy(operaBooking.getCreatedBy()); + getUser=true; + } + if(getUser) { + if(!StringUtils.isEmpty(updateBooking.getCreatedBy())) { + BaseApiResponse userInfoRes = mgmUserService.findUserInfoByUserId(updateBooking.getCreatedBy()); + if(userInfoRes.isSuccess()) { + UserInfoApiRecord userInfo = userInfoRes.getData(); + updateBooking.setBooker(userInfo.getUserName()); + updateBooking.setCreatedByName(userInfo.getUserName()); + } + } + } + + updateBookingList.add(updateBooking); + + + int expMin = 20000; +// AppSetting approvalExpMin = appSettingRepository.getByKeys(SettingConstants.APPROVAL_EXPIRE_MINUTES); +// if (approvalExpMin != null && StringUtils.isNotBlank(approvalExpMin.getKeyValues())) { +// expMin = Integer.valueOf(approvalExpMin.getKeyValues()); +// } + expMin = expMin * -1; + Date dtNow = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + dtNow = DateTimeUtil.addMin(dtNow, expMin); + + Long revisionOf = (long) 0; + for (int k = 0; k < bookingView.size(); k++) { + BookingsView bookingPending = bookingView.get(k); + + if (booking.getId().equals(bookingPending.getRevisionOf()) + && (Strings.CS.equals(bookingPending.getApproveStatus(), "PN")||Strings.CS.equals(bookingPending.getApproveStatus(), "W")) + && bookingPending.getCreatedAt().getTime() >= dtNow.getTime()) { + if (bookingPending.getId() > revisionOf) { + operaBooking.setPendingRevisionId(bookingPending.getId()); + } + revisionOf = bookingPending.getId(); + } + } + } + } + + //show opera booking in records + if (!bookingExist) { + operaBooking = this.insertOperaBooking(operaBooking,member,userId); + } + result.set(i, operaBooking); + } + + + if (!updateBookingList.isEmpty()) { + bookingDao.saveAll(updateBookingList); + } + +// if (waitlistBookingList.size() > 0) { +// bookingDao.saveAll(waitlistBookingList); +// } + + //计算cancel booking + if(!cancelBookingList.isEmpty()) { + for(BookingsView cb:cancelBookingList) { + this.processAllotment(cb.getRoomId(), cb.getCheckinDate(), cb.getCheckoutDate(), cb.getPropertyId(), cb.getBlockId()); + } + } + + // hide booking with pending revisions, instead, shows the pending version or waitlist booking + for (int j = result.size() - 1; j >= 0; j--) { + if (result.get(j).getPendingRevisionId() != null) { + result.remove(j); + } + } + + return result; + + } + + public BookingsView insertOperaBooking(BookingsView operaBooking, PlayerProfileEntry member, String userId) throws Exception { + LogUtil.info(BookingService.class,"[mergeDatabaseInfo][Opera Book Exist]"); + Date now = new Date(); + Bookings book = new Bookings(); + CfgProperties operaProperty = propertyDao.getByHotelCode(operaBooking.getHotelCode()); + CfgRoomTypes operRoomType =roomTypeDao.findByCodeAndCategory(operaBooking.getRoomTypeCode(),operaBooking.getPropertyCategory()); + CfgRooms operaRoom = new CfgRooms(); + //set room type + if(operRoomType!=null) { + List roomroomType = roomRoomTypeDao.findByRoomTypeId(operRoomType.getId()); + if(!roomroomType.isEmpty()) { + for(CfgRoomsRoomTypes r:roomroomType) { + CfgRooms room = roomDao.findById(r.getRoomId()); + if(room!=null) { + if(Objects.equals(Long.valueOf(room.getPropertyId()), operaProperty.getId())) { + operaRoom = room; + break; + } + } + } + } + + } + String operaMemberTitle = ""; + String operaMemberFirstName = ""; + String operaMemberLastName = ""; + + + String playerId =String.valueOf(member.getPlayerId()); + + book.setPlayerId(playerId); + + book.setCheckinDate(operaBooking.getCheckinDate()); + book.setCheckoutDate(operaBooking.getCheckoutDate()); + book.setPropertyId(operaProperty.getId()); + + book.setNotifyLanguage("en"); + + book.setRoom(operaRoom.getId()!=null?operaRoom.getName():""); + book.setRoomId(operaRoom.getId()!=null?operaRoom.getId():-1); + book.setRoomTypeId(operRoomType!=null?operRoomType.getId():-1); + + book.setRatePlanCode(operaBooking.getRatePlanCode()); + book.setChainCode(operaProperty.getCode()); + book.setHotelCode(operaBooking.getHotelCode()); + + book.setRoomTypeCode(operaBooking.getRoomTypeCode()); + book.setCreatedBy(operaBooking.getCreatedBy()); + book.setCreatedByName(operaBooking.getCreatedBy()); + book.setUpdatedBy(userId); + + book.setMemberTitle(operaMemberTitle); + book.setMemberFirstName(operaMemberFirstName); + book.setMemberLastName(operaMemberLastName); + + book.setMarketCode(operaBooking.getMarketCode()); + book.setDlSourceId(operaBooking.getDlSourceId()); + + book.setPaymentAmount(operaBooking.getPaymentAmount()); +// book.setGuaranteeType("CGTD"); + book.setPaymentType(null); + book.setOperaProfileId(operaBooking.getOperaProfileId()); + book.setApproveStatus("N"); + + book.setCreatedAt(DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss")); + book.setUpdatedAt(DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss")); +// book.setTeamId(objTeam.getId()); + book.setLastOperaStatus(operaBooking.getLastOperaStatus()); + book.setConfirmationNo(operaBooking.getConfirmationNo()); + book.setResvId(operaBooking.getResvId()); + book.setSharer(new JSONArray().toJSONString()); + book.setBookType("0"); + book.setDlReservationId(operaBooking.getDlReservationId()); + + //get player info + if(!StringUtils.isEmpty(book.getPlayerId())) { + BaseApiResponse serviceResult = playerService.findWebPlayerProfileByPlayerId(book.getPlayerId()); + if(serviceResult.isSuccess()) { + PlayerProfileEntry profile = serviceResult.getData(); + book.setMemberLastName(profile.getName()); + book.setMemberTitle(profile.getSalutation()); + book.setMember(JSONObject.toJSONString(profile)); + } + } + //get user info + if(!StringUtils.isEmpty(book.getCreatedBy())) { + BaseApiResponse userInfoRes = mgmUserService.findUserInfoByUserId(book.getCreatedBy()); + if(userInfoRes.isSuccess()) { + UserInfoApiRecord userInfo = userInfoRes.getData(); + book.setBooker(userInfo.getUserName()); + book.setCreatedByName(userInfo.getUserName()); + } + } + + //get Booking Type + List operaMarketCode = marketCodeDao.findByCodeAndCategory(operaBooking.getMarketCode(), "OPERA"); + List operRateCode = rateCodeDao.findByCodeAndCategory(operaBooking.getRatePlanCode(), "OPERA"); + if(!operaMarketCode.isEmpty() && !operRateCode.isEmpty()) { + Long operaMarketCodeId = operaMarketCode.getFirst().getId(); + Long operaRateCodeId = operRateCode.getFirst().getId(); + List bookingTypeOperas = daylightViewDao.findByMarketCodeIdAndRateCodeId(operaMarketCodeId,operaRateCodeId); + if(!bookingTypeOperas.isEmpty()) { + Long operaBookingTypeId = bookingTypeOperas.getFirst().getBookingTypeId(); + book.setBookingTypeId(operaBookingTypeId); + } + } + + + // build datelist + int numOfNight = Integer.parseInt(DateTimeUtil.getDiffDate(book.getCheckinDate(), book.getCheckoutDate(), "day")); + ArrayList dates = new ArrayList<>(); + ArrayList dateList = new ArrayList<>(); + JSONObject obj = new JSONObject(); + for(int j=0;j checkOperaBookExist = bookingViewDao.findByConfirmationNo(operaBooking.getConfirmationNo()); + Long operaBookId = (long) 0; + if(checkOperaBookExist!=null) { + book = bookingDao.save(book); + operaBookId = book.getId(); + }else { + operaBookId = checkOperaBookExist.getFirst().getId(); + LogUtil.info(BookingService.class,"[mergeDatabaseInfo][Exists,No Saved Opera Book ]"); + } + + operaBooking.setId(operaBookId); + operaBooking.setPlayerId(playerId); + operaBooking.setPropertyId(operaProperty.getId()); + operaBooking.setPropertyName(operaProperty.getName()); + operaBooking.setNotifyLanguage("en"); + + operaBooking.setUpdatedBy(userId); + operaBooking.setCreatedBy(operaBooking.getCreatedBy()); + + operaBooking.setMemberTitle(operaMemberTitle); + operaBooking.setMemberFirstName(operaMemberFirstName); + operaBooking.setMemberLastName(operaMemberLastName); + + operaBooking.setPaymentAmount(operaBooking.getPaymentAmount()); + operaBooking.setUpdatedAt(now); + operaBooking.setApproveStatus("N"); + operaBooking.setCreatedAt(now); + + return operaBooking; + } + + @Transactional + public BookingsView insertDaylightBooking(BookingsView operaBooking, PlayerProfileEntry member, String userId) throws Exception { + LogUtil.info(BookingService.class,"[mergeDatabaseInfo][Opera Book Exist]"); + Date now = new Date(); + Bookings book = new Bookings(); + CfgProperties operaProperty = propertyDao.getByPropertyNameDaylight(operaBooking.getPropertyName()); + CfgRoomTypes operRoomType =roomTypeDao.findByCodeAndCategory(operaBooking.getRoomTypeCode(), "DAYLIGHT"); + CfgRooms operaRoom = new CfgRooms(); + //set room type + if(operRoomType!=null) { + List roomroomType = roomRoomTypeDao.findByRoomTypeId(operRoomType.getId()); + if(!roomroomType.isEmpty()) { + for(CfgRoomsRoomTypes r:roomroomType) { + CfgRooms room = roomDao.findById(r.getRoomId()); + if(room!=null) { + if(Long.valueOf(room.getPropertyId()).equals(operaProperty.getId())) { + operaRoom = room; + break; + } + } + } + } + } + String operaMemberTitle = ""; + String operaMemberFirstName = ""; + String operaMemberLastName = ""; + + + String playerId =member.getPlayerId(); + + book.setPlayerId(playerId); + + book.setCheckinDate(operaBooking.getCheckinDate()); + book.setCheckoutDate(operaBooking.getCheckoutDate()); + book.setPropertyId(operaProperty.getId()); + + book.setNotifyLanguage("en"); + + book.setRoom(operaRoom.getId()!=null?operaRoom.getName():""); + book.setRoomId(operaRoom.getId()!=null?operaRoom.getId():-1); + book.setRoomTypeId(operRoomType!=null?operRoomType.getId():-1); + + book.setRatePlanCode(operaBooking.getRatePlanCode()); + book.setChainCode(operaProperty.getCode()); + book.setHotelCode(operaBooking.getHotelCode()); + + book.setRoomTypeCode(operRoomType.getCode()); + book.setRoomId(operaRoom.getId()!=null?operaRoom.getId():-1); + book.setCreatedBy(operaBooking.getCreatedBy()); + book.setCreatedByName(operaBooking.getCreatedBy()); + book.setUpdatedBy(userId); + + book.setMemberTitle(operaMemberTitle); + book.setMemberFirstName(operaMemberFirstName); + book.setMemberLastName(operaMemberLastName); + + book.setMarketCode(operaBooking.getMarketCode()); + book.setDlSourceId(operaBooking.getDlSourceId()); + + book.setPaymentAmount(operaBooking.getPaymentAmount()); + book.setPaymentType(null); + book.setApproveStatus("N"); + + book.setCreatedAt(DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss")); + book.setUpdatedAt(DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss")); +// book.setTeamId(objTeam.getId()); + book.setLastOperaStatus(operaBooking.getLastOperaStatus()); + book.setConfirmationNo(operaBooking.getConfirmationNo()); + book.setResvId(operaBooking.getResvId()); + book.setSharer(new JSONArray().toJSONString()); + book.setBookType("0"); + book.setDlReservationId(operaBooking.getDlReservationId()); + + //get player info + if(!StringUtils.isEmpty(book.getPlayerId())) { + BaseApiResponse serviceResult = playerService.findWebPlayerProfileByPlayerId(book.getPlayerId()); + if(serviceResult.isSuccess()) { + PlayerProfileEntry profile = serviceResult.getData(); + book.setMemberLastName(profile.getName()); + book.setMemberTitle(profile.getSalutation()); + book.setMember(JSONObject.toJSONString(profile)); + } + } + //get user info + if(!StringUtils.isEmpty(book.getCreatedBy())) { + BaseApiResponse userInfoRes = mgmUserService.findUserInfoByUserId(book.getCreatedBy()); + if(userInfoRes.isSuccess()) { + UserInfoApiRecord userInfo = userInfoRes.getData(); + book.setBooker(userInfo.getUserName()); + book.setCreatedByName(userInfo.getUserName()); + } + } + + //get Booking Type + List operaMarketCode = marketCodeDao.findByCodeAndCategory(operaBooking.getMarketCode(), "DAYLIGHT"); + List operRateCode = rateCodeDao.findByCodeAndCategory(operaBooking.getRatePlanCode(), "DAYLIGHT"); + if(!operaMarketCode.isEmpty() && !operRateCode.isEmpty()) { + Long operaMarketCodeId = operaMarketCode.getFirst().getId(); + Long operaRateCodeId = operRateCode.getFirst().getId(); + List bookingTypeOperas = daylightViewDao.findByMarketCodeIdAndRateCodeId(operaMarketCodeId,operaRateCodeId); + if(!bookingTypeOperas.isEmpty()) { + Long operaBookingTypeId = bookingTypeOperas.getFirst().getBookingTypeId(); + book.setBookingTypeId(operaBookingTypeId); + } + } + + + // build datelist + int numOfNight = Integer.parseInt(DateTimeUtil.getDiffDate(book.getCheckinDate(), book.getCheckoutDate(), "day")); + ArrayList dates = new ArrayList<>(); + ArrayList dateList = new ArrayList<>(); + JSONObject obj = new JSONObject(); + for(int j=0;j checkOperaBookExist = bookingViewDao.findByConfirmationNo(operaBooking.getConfirmationNo()); + Long operaBookId = (long) 0; + if(checkOperaBookExist!=null) { + book = bookingDao.save(book); + operaBookId = book.getId(); + }else { + operaBookId = checkOperaBookExist.getFirst().getId(); + LogUtil.info(BookingService.class,"[mergeDatabaseInfo][Exists,No Saved Opera Book ]"); + } + + operaBooking.setId(operaBookId); + operaBooking.setPlayerId(playerId); + operaBooking.setPropertyId(operaProperty.getId()); + operaBooking.setPropertyName(operaProperty.getName()); + operaBooking.setNotifyLanguage("en"); + + operaBooking.setUpdatedBy(userId); + operaBooking.setCreatedBy(operaBooking.getCreatedBy()); + + operaBooking.setMemberTitle(operaMemberTitle); + operaBooking.setMemberFirstName(operaMemberFirstName); + operaBooking.setMemberLastName(operaMemberLastName); + + operaBooking.setPaymentAmount(operaBooking.getPaymentAmount()); + operaBooking.setUpdatedAt(now); + operaBooking.setApproveStatus("N"); + operaBooking.setCreatedAt(now); + + return operaBooking; + } + + public String getStartDate(String startdate,int maxNights) { + String returnDate = ""; + + Date date = DateTimeUtil.getDateFromString(startdate,"yyyy-MM-dd"); + date = DateTimeUtil.addDay(date, -1 * maxNights); + returnDate = DateTimeUtil.getDateByFormat(date,"yyyy-MM-dd"); + + return returnDate; + } + public String getSearchRecordCheckOutDate(String startdate) { + String returnDate = ""; + + Date date = DateTimeUtil.getDateFromString(startdate,"yyyy-MM-dd"); + date = DateTimeUtil.addYear(date, 2); + returnDate = DateTimeUtil.getDateByFormat(date,"yyyy-MM-dd"); + + return returnDate; + } + + public List getSearchRecordPending(String checkinDate, + String checkoutDate, String playerId) { + // 获得配置的过期分钟 暂无 +// AppSetting approvalExpMin = appSettingRepository.getByKeys(SettingConstants.APPROVAL_EXPIRE_MINUTES); +// if (approvalExpMin != null && StringUtils.isNotBlank(approvalExpMin.getKeyValues())) { +// expMin = Integer.valueOf(approvalExpMin.getKeyValues()); +// } + boolean isMock = sysSettingService.isAPPMock(); + int expMin = 20000; + expMin = expMin * -1; + + Date dtNow = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + dtNow = DateTimeUtil.addMin(dtNow, expMin); + String nowStr = DateTimeUtil.getDateByFormat(dtNow, "yyyy-MM-dd HH:mm:ss"); + + return bookingViewDao.findRecordSearchPending(playerId, checkinDate, + checkoutDate, nowStr); + } + + public List getBookingsByGroupId(String groupId) { + return bookingViewDao.findBookingsByGroupId(groupId); + } + + public List getBookingForRefreshGamingData(BookingQueryRequest queryFilter){ + Specification listSpec = buildSpecificationViewByQueryFilter(queryFilter); + Sort sort = DaoUtil.buildSortByFilter(queryFilter.getSortOrder(), "id"); + return bookingViewDao.findAll(listSpec,sort); + } + + public List getBookingByDaylightConf(String conf) { + List list = bookingViewDao.findBookingByConfirmationNo(conf); + return list; + } + + public List getBookingByConfirmationNo(String conf) throws Exception { + + List list = bookingViewDao.findBookingByConfirmationNo(conf); + + if (CollectionUtils.isEmpty(list)) { + return Collections.emptyList(); + } + + if ("DAYLIGHT".equalsIgnoreCase(list.getFirst().getPropertyCategory())) { + return getBookingDaylight(list); + } + + return getBookingOperaOther(list, conf); + } + + private List getBookingOperaOther(List list, String conf) { + List operaList = operaDBService.getBookingsByConfirmationNo(conf); + + for(int i=0;i0) + { + for(int j=0;j0) { + BookingsView operaBook = operaList.get(0); + expDate = StringUtils.upperCase(operaBook.getExpDate()); + String profileExpDate = StringUtils.upperCase(operaBook.getProfieExpDate()); + LogUtil.info(BookingService.class, + "[getBookingByConfirmationNo] profileExpDate " + operaBook.getProfieExpDate()); + expDate = profileExpDate; + + //set is queue + booking.setQueue(operaBook.isQueue()); + } + +// if(!StringUtils.isEmpty(profileExpDate)) { +// if(StringUtils.isEmpty(expDate)||StringUtils.contains(expDate, "FORM")) { +// expDate = profileExpDate; +// }else { +// Date edateTime = DateTimeUtil.getDateFromString(expDate, "yyyy-MM-dd"); +// Date proEdateTime = DateTimeUtil.getDateFromString(profileExpDate, "yyyy-MM-dd"); +// if(proEdateTime.getTime()0) { + for (int a = 0; a < dynList.size(); a++) { + JSONObject shareObj = (JSONObject) dynList.get(a); + String shareConfirmationNo = shareObj.getString("confirmation_no"); + if(!StringUtils.isEmpty(shareConfirmationNo)) { + List shareOperaList = operaDBService.getBookingsByConfirmationNo(shareConfirmationNo); + if(shareOperaList!=null&&shareOperaList.size()>0) { + BookingsView sharerOperaBooking = shareOperaList.get(0); + String shareProfileExpDate = sharerOperaBooking.getProfieExpDate(); + LogUtil.info(BookingService.class, + "[getBookingByConfirmationNo] shareProfileExpDate " + sharerOperaBooking.getProfieExpDate()); + if(StringUtils.isEmpty(shareProfileExpDate)) { + expDate = shareProfileExpDate; + } else if(StringUtils.contains(shareProfileExpDate, "FORM")){ + + }else { + if(!StringUtils.isEmpty(expDate)&&!StringUtils.contains(expDate, "FORM")) { + Date edateTime = DateTimeUtil.getDateFromString(expDate, "yyyy-MM-dd"); + Date proShareEdateTime = DateTimeUtil.getDateFromString(shareProfileExpDate, "yyyy-MM-dd"); + if(proShareEdateTime.getTime() dates = new ArrayList(); + ArrayList dateList = new ArrayList(); + JSONObject obj = new JSONObject(); + Integer numOfNight = Integer.valueOf(DateTimeUtil.getDiffDate(booking.getCheckinDate(), booking.getCheckoutDate(), "day")); + booking.setNumOfNight(numOfNight); + // build datelist + for(int j=0;j getBookingDaylight(List list) { + if (list == null || list.isEmpty()) { + return list; + } + + String dlReservationId = list.stream() + .map(BookingsView::getDlReservationId) + .filter(Objects::nonNull) + .findFirst() + .orElse(null); + + propertyCache.refresh(); + + DaylightReservationResponse daylightResultBooking = null; + + String dlPropertyId = null; + + if (dlReservationId != null) { + for (CfgProperties cfgProperties : propertyCache.getProperties()) { + daylightResultBooking = dlService.getDaylightReservationByDlId( + dlReservationId, + cfgProperties.getDlPropertyId() + ); + if (daylightResultBooking != null) { + dlPropertyId = cfgProperties.getDlPropertyId(); + break; + } + } + } + + if (daylightResultBooking == null) { + daylightResultBooking = new DaylightReservationResponse(); + } + + if (CollectionUtils.isEmpty(daylightResultBooking.getExternalIds())) { + String dlExternalNo = "UP2-" + UUID.randomUUID().toString().replace("-", ""); + + dlService.daylightSetExternalNo( + dlPropertyId, + dlReservationId, + dlExternalNo, + daylightResultBooking.getVersion() + ); + } + + for (BookingsView view : list) { + if ("FC".equals(view.getApproveStatus()) && view.getConfirmationNo() != null) { + view.setApproveStatus("N"); + } + + if (StringUtils.isNotBlank(view.getFeatureCode())) { + String specialName = Arrays.stream(view.getFeatureCode().split(",")) + .filter(StringUtils::isNotBlank) + .map(roomFeatureDao::getByDaylightCode) + .filter(Objects::nonNull) + .map(CfgRoomFeatures::getDescription) + .collect(Collectors.joining(", ")); + view.setSpecialName(specialName); + } + + String expDate = ""; + + view.setDlSharerIds(daylightResultBooking.getAccompanyingGuestProfileIds()); + view.setDlVersion(daylightResultBooking.getVersion()); + + BaseApiResponse> profileResult = + dlService.dayLightGetProfileByPlayerId(view.getPlayerId()); + + if (profileResult == null || profileResult.getData() == null || profileResult.getData().isEmpty()) { + // 查不到主 guest 的 profile,expDate 直接置空 + expDate = null; + } else { + ProfileDetailResponse profile = profileResult.getData().getFirst(); + if (profile == null || profile.getCustomFieldContainerJson() == null) { + // 主 guest 的 customFieldContainerJson 为 null,expDate 直接置空 + expDate = null; + } else { + JSONObject json = JSONObject.parseObject(profile.getCustomFieldContainerJson()); + String mainExpDate = json.getString("CanStayUntil"); + if (mainExpDate == null) { + // 主 guest 的 CanStayUntil 为 null,expDate 直接置空 + expDate = null; + } else { + expDate = mainExpDate; + } + } + } + + if (StringUtils.isNotBlank(view.getSharer()) && !"[]".equals(view.getSharer())) { + JSONArray sharerList = JSONArray.parseArray(view.getSharer()); + view.setSharerList(sharerList); + + for (String dlSharerId : view.getDlSharerIds()) { + ProfileDetailResponse profileDetailResponse + = dlService.dayLightGetProfileByProfileId(dlSharerId); + + if (profileDetailResponse == null || profileDetailResponse.getCustomFieldContainerJson() == null) { + // 查不到 profile 或 customFieldContainerJson,expDate 直接置空并跳出 + expDate = null; + break; + } + + JSONObject json = JSONObject.parseObject(profileDetailResponse.getCustomFieldContainerJson()); + String shareExpDate = json.getString("CanStayUntil"); + if (shareExpDate == null) { + // CanStayUntil 为 null,expDate 直接置空并跳出 + expDate = null; + break; + } + + if (StringUtils.isBlank(expDate)) { + 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; + } + } + } + } + + view.setExpDate(expDate); + + int numOfNight = Integer.parseInt( + DateTimeUtil.getDiffDate( + view.getCheckinDate(), + view.getCheckoutDate(), + "day" + ) + ); + + view.setNumOfNight(numOfNight); + + ArrayList dates = new ArrayList<>(); + for (int j = 0; j <= numOfNight; j++) { + dates.add(DateTimeUtil.getDateByFormat( + DateTimeUtil.addDay(view.getCheckinDate(), j), + "yyyy-MM-dd" + )); + } + + JSONObject dateObj = new JSONObject(); + dateObj.put("date", dates); + dateObj.put("numOfNight", numOfNight); + dateObj.put("numOfRoom", 1); + dateObj.put("checked", true); + + ArrayList dateList = new ArrayList<>(); + dateList.add(dateObj); + view.setDateList(dateList); + } + + return list; + } + + public List getBookingById(long id) { + + List list = bookingViewDao.findBookingById(id); + + if(list!=null && list.size()>0) { + for(int i=0;i0) { + for(int j=0;j dates = new ArrayList(); + ArrayList dateList = new ArrayList(); + JSONObject obj = new JSONObject(); + // build datelist + for(int j=0;j0) { + for (String s : arrSpecialCode) { + if (!s.isEmpty()) { + CfgRoomFeatures features = roomFeatureDao.getByOperaCode(s); + if (features != null) { + specialRequests.add(features.getCode()); + } + } + } + } + } + if(!specialRequests.isEmpty()) createRequest.setSpecialRequests(specialRequests); + + if(booking.getOperaProfileId()==null) { + List profileIdList = new ArrayList<>(); + if(booking.getPlayerId()!=null) { + profileIdList = operaDBService.getOperaNameIDByPlayerID(booking.getPlayerId()); + } + if (!profileIdList.isEmpty()) { + booking.setOperaProfileId(Long.valueOf(profileIdList.getFirst())); + }else { + String bookNameStr = Strings.CS.replace(booking.getMemberLastName(), ", ", ";"); + String[] bookNameArr = StringUtils.split(bookNameStr, ";"); + if(bookNameArr.length>1) { + booking.setMemberFirstName(bookNameArr[1]); + booking.setMemberLastName(bookNameArr[0]); + } + } + } + + //If room type failed ,reget room type + booking = this.getBookingRoomType(booking); + + createRequest.setBooking(booking); + LogUtil.info(BookingService.class, + "[callOWSCreateBooking] booking " + gson.toJson(booking)); + JSONObject createBookResponse = new JSONObject(); + createBookResponse = operaService.createBooking(createRequest); + LogUtil.info(BookingService.class, + "[Reservation] createBookResponse " + createBookResponse.toJSONString()); + JSONObject errors = new JSONObject(); + boolean createProfile = booking.getOperaProfileId() == null; + if (!createBookResponse.isEmpty()) { + if (createBookResponse.get("internal_id") != null) { + booking.setConfirmationNo(createBookResponse.get("internal_id") != null + ? String.valueOf(createBookResponse.get("internal_id")) + : ""); + booking.setResvId( + createBookResponse.get("resv_id") != null ? String.valueOf(createBookResponse.get("resv_id")) + : ""); + booking.setOperaProfileId(createBookResponse.get("profile_id") != null + ? Long.valueOf(String.valueOf(createBookResponse.get("profile_id"))) + : null); + booking.setOperaTotal( + createBookResponse.get("total") != null ? Double.valueOf(String.valueOf(createBookResponse.get("total"))) : null); + booking.setApproveStatus("N"); + booking.setUpdatedAt(DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss")); + booking.setErrorMessage(null); + + if(createProfile) { + LogUtil.info(BookingService.class, + "[Reservation] createProfile " + booking.getOperaProfileId()); + InsertGuestCardRequest insertGuestCardRequest = new InsertGuestCardRequest(); + JSONObject insertGuestCardResponse = new JSONObject(); + insertGuestCardRequest.setMemberName(booking.getMemberLastName()); + insertGuestCardRequest.setNameId(String.valueOf(booking.getOperaProfileId())); + insertGuestCardRequest.setPlayerId(booking.getPlayerId()); + insertGuestCardResponse = operaService.insertGuestCard(insertGuestCardRequest); + + + if(booking.getMember()!=null&&!StringUtils.isEmpty(booking.getMember())) { + JSONObject memberObj = JSONObject.parseObject(booking.getMember()); + if(memberObj.containsKey("passport")&&memberObj.get("passport")!=null&&!memberObj.getString("passport").isEmpty()){ + UpdatePassportRequest updatePassportRequest = new UpdatePassportRequest(); + JSONObject updatePassportResponse = new JSONObject(); + updatePassportRequest.setNameId(String.valueOf(booking.getOperaProfileId())); + updatePassportRequest.setNumber(memberObj.getString("passport")); + updatePassportResponse = operaService.updatePassport(updatePassportRequest); + } + } + + } + BookingsView viewBook = bookingViewDao.findById(booking.getId()).orElse(null); + String bookComment = operaService.makeCashierComment(viewBook); + + Bookings successBook = bookingDao.save(booking); + + LogUtil.info(BookingService.class, + "[Reservation] New Booking " + createBookResponse.get("internal_id") + " made. PlayerId=" + + booking.getPlayerId() + " username=" + booking.getCreatedBy()); + + CfgProperties property = propertyDao.getById(booking.getPropertyId()); + GuestRequestsRequest cashCommentRequest = new GuestRequestsRequest(); + JSONObject cashCommentResponse = new JSONObject(); + cashCommentRequest.setActionType("ADD"); + cashCommentRequest.setProperty(property); + cashCommentRequest.setComment(bookComment); + cashCommentRequest.setConfirmationNo(booking.getConfirmationNo()); + cashCommentRequest.setCommentType("CASHIER"); + cashCommentResponse = operaService.guestRequests(cashCommentRequest); + + //Delete dupulicate booking + bookingDao.deleteDuplicateBooking(booking.getId(),booking.getConfirmationNo()); + + //share booking + booking = this.syncBookingSharer(booking,successBook,property); + + //update waitlist booking + if(booking.getWaitlistId()!=null) { + Bookings waitlistBooking = bookingDao.findById(booking.getWaitlistId()).orElse(null); + waitlistBooking.setConfirmationNo(booking.getConfirmationNo()); + waitlistBooking.setApproveStatus("WF"); + waitlistBooking.setUpdatedAt(DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss")); + bookingDao.save(waitlistBooking); + } + + //计算allotment + this.processAllotment(viewBook.getRoomId(), viewBook.getCheckinDate(), viewBook.getCheckoutDate(), viewBook.getPropertyId(), viewBook.getBlockId()); + + bookingDao.updateProcessStatus(booking.getId(), 0); + + return; + } + } + errors = createBookResponse; + Integer trytime = booking.getTryTime()==null?0:(booking.getTryTime()+1); + booking.setTryTime(trytime); + booking.setErrorMessage(errors.getString("message")!=null?errors.getString("message"):"System Error"); + booking.setApproveStatus("F"); + booking.setFailedAt(DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss")); + booking.setProcessStatus(0); + if(Strings.CS.contains(booking.getErrorMessage(), "No available room")) { + String failedRoomType= booking.getFailedRoomType(); + if(!StringUtils.isEmpty(failedRoomType)) { + if(!Strings.CS.contains(failedRoomType, booking.getRoomTypeCode())) { + failedRoomType = failedRoomType+";"+booking.getRoomTypeCode(); + booking.setFailedRoomType(failedRoomType); + } + }else { + booking.setFailedRoomType(booking.getRoomTypeCode()); + } + } + + ArrayList booksList = new ArrayList(); + booksList.add(booking); + sysLogBookingService.saveLogBooking(booksList, null, "", "", "Sync Opera Failed",""); + + bookingDao.save(booking); + } + } + + public JSONObject callOWSEditBooking(Bookings booking) throws Exception { + boolean isMock = sysSettingService.isMockReplicate(); + JSONObject modifyBookingResponse = new JSONObject(); + if(isMock) { + if(booking.getPropertyId()!=5&&booking.getPropertyId()!=6) { +// Thread.sleep(60000); + booking.setApproveStatus("N"); + bookingDao.save(booking); + Bookings originBooking = bookingDao.findById(booking.getRevisionOf()).orElse(null); + originBooking.setCheckoutDate(booking.getCheckoutDate()); + Integer numOfNight = Integer.valueOf(DateTimeUtil.getDiffDate(originBooking.getCheckinDate(), originBooking.getCheckoutDate(), "day")); + ArrayList dates = new ArrayList(); + ArrayList dateList = new ArrayList(); + JSONObject obj = new JSONObject(); + // build datelist + for(int j=0;j dates = new ArrayList(); + ArrayList dateList = new ArrayList(); + JSONObject obj = new JSONObject(); + // build datelist + for(int j=0;j waitlistBooking = bookingViewDao.findWaitlistBooking(); + Date now = new Date(); + for(BookingsView book:waitlistBooking) { + List returnBooking = new ArrayList(); + if(isMock) { + returnBooking = bookingViewDao.findByPlayerId(book.getPlayerId()); + }else { +// returnBooking = operaDBService.getBookingsByNameID(String.valueOf(book.getOperaProfileId()), "All", null); + } + for(BookingsView rBook:returnBooking) { + if(book.getConfirmationNo()!=null&&Strings.CS.equals(book.getConfirmationNo(), rBook.getConfirmationNo())) { //extend +// if(rBook.getCheckoutDate()==book.getCheckoutDate()) { +// Bookings waitBook = bookingDao.findById(book.getId()); +// waitBook.setUpdatedAt(now); +// waitBook.setApproveStatus("N"); +// bookingDao.save(waitBook); +// break; +// } + if(isMock&&!Strings.CS.equals(rBook.getApproveStatus(),"N")) continue; + + Bookings waitBook = bookingDao.findById(book.getId()).orElse(null); + Bookings originBook = bookingDao.findById(rBook.getId()).orElse(null); + waitBook.setUpdatedAt(now); + waitBook.setApproveStatus("WF"); + bookingDao.save(waitBook); + originBook.setBookType("1"); + originBook.setCheckoutDate(waitBook.getCheckoutDate()); + originBook.setNumOfNight(originBook.getNumOfNight()+book.getNumOfNight()); + bookingDao.save(originBook); + + //Dedute app channel + JSONArray extendDateList = JSONArray.parseArray( book.getDateLists()); + JSONObject date = (JSONObject) extendDateList.getFirst(); + JSONArray dateArr = (JSONArray) date.get("date"); + Date checkInDate = DateTimeUtil.getDateFromString(String.valueOf(dateArr.getFirst()), "yyyy-MM-dd"); + Date checkOutDate = DateTimeUtil.getDateFromString(String.valueOf(dateArr.getLast()), "yyyy-MM-dd"); + this.processAllotment(book.getRoomId(), checkInDate, checkOutDate, book.getPropertyId(), book.getBlockId()); + break; + }else { + if(rBook.getCheckinDate().getTime()==book.getCheckinDate().getTime()&& + rBook.getCheckoutDate().getTime()==book.getCheckoutDate().getTime()) { //new + Bookings waitBook = bookingDao.findById(book.getId()).orElse(null); + if(!StringUtils.isEmpty(waitBook.getConfirmationNo())) break; //No duplicate update + if(isMock) { + Random random = new Random(); + int randomNumber = random.nextInt(10000000); + waitBook.setConfirmationNo(String.valueOf(randomNumber)); + waitBook.setResvId(String.valueOf(randomNumber)); + waitBook.setApproveStatus("WF"); + Bookings newBook = new Bookings(); + BeanUtils.copyProperties(waitBook, newBook); + newBook.setId(null); + newBook.setApproveStatus("N"); + newBook.setLastOperaStatus("RESERVED"); + bookingDao.save(newBook); + }else { + waitBook.setConfirmationNo(rBook.getConfirmationNo()); + waitBook.setResvId(rBook.getResvId()); + } + waitBook.setUpdatedAt(now); + bookingDao.save(waitBook); + + //Dedute app channel + this.processAllotment(book.getRoomId(), book.getCheckinDate(), book.getCheckoutDate(), book.getPropertyId(), book.getBlockId()); + break; + } + } + } + } + } + + public JSONArray getBookingRates(Bookings book,Date startEndDate) { + JSONArray bookingRates = new JSONArray(); + Calendar calendar = Calendar.getInstance(); + String checkinStr = DateTimeUtil.getDateByFormat(startEndDate, "yyyy-MM-dd"); + String checkoutStr = DateTimeUtil.getDateByFormat(book.getCheckoutDate(), "yyyy-MM-dd"); + List rateList = operaDBService.getBookingsRate(book.getRatePlanCode(),book.getRoomTypeCode(),checkinStr,checkoutStr); + if(rateList!=null&&rateList.size()>0) { + Gson gson = new Gson(); + Date checkoutDate = book.getCheckoutDate(); + long checkoutDateTime = DateTimeUtil.getLongFromDate(checkoutDate); + long endDate = DateTimeUtil.getLongFromDate(startEndDate); + LogUtil.info(BookingService.class, + "[getBookingRates] endDate:" + gson.toJson(endDate)); + LogUtil.info(BookingService.class, + "[getBookingRates] checkoutDateTime:" + gson.toJson(checkoutDateTime)); + LogUtil.info(BookingService.class, + "[getBookingRates] rateList:" + gson.toJson(rateList)); + while(endDate<=checkoutDateTime){ + boolean isCurrentRate = false; + Date currentDate = DateTimeUtil.getDateFromLong(endDate); + calendar.setTime(currentDate); + int bDay= calendar.get(Calendar.DAY_OF_WEEK); + LogUtil.info(BookingService.class, + "[getBookingRates] currentDate:" + gson.toJson(DateTimeUtil.getDateByFormat(currentDate, "yyyy-MM-dd"))); + LogUtil.info(BookingService.class, + "[getBookingRates] bDay:" + gson.toJson(bDay)); + for(OperaDBRate rates : rateList) { + LogUtil.info(BookingService.class, + "[getBookingRates] rates:" + gson.toJson(rates)); + if(bDay==1) { //sunday + if(Strings.CS.equals(rates.getDay1(), "Y")) isCurrentRate = true; + }else if(bDay==2) { + if(Strings.CS.equals(rates.getDay2(), "Y")) isCurrentRate = true; + }else if(bDay==3) { + if(Strings.CS.equals(rates.getDay3(), "Y")) isCurrentRate = true; + }else if(bDay==4) { + if(Strings.CS.equals(rates.getDay4(), "Y")) isCurrentRate = true; + }else if(bDay==5) { + if(Strings.CS.equals(rates.getDay5(), "Y")) isCurrentRate = true; + }else if(bDay==6) { + if(Strings.CS.equals(rates.getDay6(), "Y")) isCurrentRate = true; + }else if(bDay==7) { + if(Strings.CS.equals(rates.getDay7(), "Y")) isCurrentRate = true; + } + + Date rateBeginDate = DateTimeUtil.getDateFromString(rates.getBeginDate(), "yyyy-MM-dd"); + Date rateEndDate = DateTimeUtil.getDateFromString(rates.getEndDate(), "yyyy-MM-dd"); + + LogUtil.info(BookingService.class, + "[getBookingRates] datePeriod:" + gson.toJson(currentDate.getTime()<=rateEndDate.getTime()&¤tDate.getTime()>=rateBeginDate.getTime())); + if(!(currentDate.getTime()<=rateEndDate.getTime()&¤tDate.getTime()>=rateBeginDate.getTime())) { + isCurrentRate = false; + } + + LogUtil.info(BookingService.class, + "[getBookingRates] isCurrentRate:" + gson.toJson(isCurrentRate)); + if(isCurrentRate) { + JSONObject rateObject = new JSONObject(); + rateObject.put("date", DateTimeUtil.getDateByFormat(currentDate, "yyyy-MM-dd")); + rateObject.put("rate",rates.getAmount1()); + LogUtil.info(BookingService.class, + "[getBookingRates] rateObject:" + gson.toJson(rateObject)); + bookingRates.add(rateObject); + break; + } + } + endDate = DateTimeUtil.getLongFromDate(DateTimeUtil.addDay(DateTimeUtil.getDateFromLong(endDate), 1)); + } + } + return bookingRates; + } + + public boolean checkRoomNo(Long id,String checkinDate, String checkoutDate) { + boolean isMock = sysSettingService.isMockReplicate(); + if(isMock) return true; + Bookings book = bookingDao.findById(id).orElse(null); + List results = new ArrayList(); + List roomList = new ArrayList(); + long startDate = DateTimeUtil.getLongFromDate(DateTimeUtil.getDateFromString(checkinDate,"yyyy-MM-dd")); + long endDate = DateTimeUtil.getLongFromDate(DateTimeUtil.getDateFromString(checkoutDate,"yyyy-MM-dd")); + results = operaDBService.getBookingsByConfirmationNo(book.getConfirmationNo()); + + if(results.size()>0) { + roomList = operaDBService.getBookingsByRoomNo(results.getFirst().getRoomNo()); + }else { + return false; + } + if(roomList.size()>0) { + for(int i = 0;i=roomStartDate&&startDateroomStartDate&&endDate<=roomEndDate) || + (startDateroomEndDate) ) return false; + } + } + } + return true; + }else { + return true; + } + } + + private Bookings getBookingRoomType(Bookings booking) throws Exception { + if(Strings.CS.contains(booking.getErrorMessage(), "No available room")) { + List roomTypes = new ArrayList(); + List bedTypes = new ArrayList(); + String roomTypeCode = ""; + Long roomTypeId = null; + String[] failedRoomTypeArr = StringUtils.split(booking.getFailedRoomType(),";"); + if(booking.getBedTypeMasterGroupId()==null) { + roomTypes = roomRoomTypeDao.queryByRoomId(booking.getRoomId()); + if(roomTypes!=null && roomTypes.size()>0) { + ArrayList failedRoomType = new ArrayList(); + for(int z=0;z0) { + HashMap roomTypeMap = new HashMap(); + roomTypeMap.put("num",failedNum); + roomTypeMap.put("id",roomTypeId); + roomTypeMap.put("type",roomTypeCode); + failedRoomType.add(roomTypeMap); + roomTypeId = null; + roomTypeCode = null; + continue; + }else { + break; + } + } + } + if(StringUtils.isEmpty(roomTypeCode)) { + if(failedRoomType.size()>0) { + HashMap getRoomType = new HashMap(); + for(int a=0;a0) { + ArrayList failedRoomType = new ArrayList(); + for(int z=0;z0) { + HashMap roomTypeMap = new HashMap(); + roomTypeMap.put("num",failedNum); + roomTypeMap.put("id",roomTypeId); + roomTypeMap.put("type",roomTypeCode); + failedRoomType.add(roomTypeMap); + roomTypeId = null; + roomTypeCode = null; + continue; + }else { + break; + } + } + } + //if no bed type room,get all room type + if(StringUtils.isEmpty(roomTypeCode)) { + roomTypes = roomRoomTypeDao.queryByRoomId(booking.getRoomId()); + if(roomTypes!=null && roomTypes.size()>0) { + for(int z=0;z0) { + HashMap roomTypeMap = new HashMap(); + roomTypeMap.put("num",failedNum); + roomTypeMap.put("id",roomTypeId); + roomTypeMap.put("type",roomTypeCode); + failedRoomType.add(roomTypeMap); + roomTypeId = null; + roomTypeCode = null; + continue; + }else { + break; + } + } + } + } + } + if(StringUtils.isEmpty(roomTypeCode)) { + if(failedRoomType.size()>0) { + HashMap getRoomType = new HashMap(); + for(int a=0;a shareConfirmationNo = new ArrayList<>(); + List successShareBooks = new ArrayList<>(); + for (int a = 0; a < dynList.size(); a++) { + CreateBookingRequest createSharerRequest = new CreateBookingRequest(); + Bookings shareBook = gson.fromJson(gson.toJson(successBook),Bookings.class); + JSONObject shareObj = dynList.getJSONObject(a); + String sharePlayerId = shareObj.getString("playerId"); + String shareName = shareObj.getString("name"); + LogUtil.info(BookingService.class, + "[synvBookingSharer] sharePlayerId " + gson.toJson(sharePlayerId)); + LogUtil.info(BookingService.class, + "[synvBookingSharer] shareName " + gson.toJson(shareName)); + if(!StringUtils.isEmpty(sharePlayerId)) { + shareBook.setPlayerId(sharePlayerId); + List profileIdList = new ArrayList(); + profileIdList = operaDBService.getOperaNameIDByPlayerID(sharePlayerId); + LogUtil.info(BookingService.class, + "[synvBookingSharer] profileIdList " + gson.toJson(profileIdList)); +// if (profileIdList.size()>0) { +// shareBook.setOperaProfileId(Long.valueOf(profileIdList.get(0))); +// }else { +// shareBook.setOperaProfileId(null); +// } +// + String shareNameStr = Strings.CS.replace(shareName, ", ", ";"); + String[] shareNameArr = StringUtils.split(shareNameStr, ";"); + if(shareNameArr.length>1) { + shareBook.setMemberFirstName(shareNameArr[1]); + shareBook.setMemberLastName(shareNameArr[0]); + }else { + shareBook.setMemberLastName(shareName); + } + }else if(!StringUtils.isEmpty(shareName)) { +// shareBook.setOperaProfileId(null); + shareBook.setPlayerId(null); + String[] shareNameArr = StringUtils.split(shareName, ", ",2); + if(shareNameArr.length>1) { + shareBook.setMemberFirstName(shareNameArr[1]); + shareBook.setMemberLastName(shareNameArr[0]); + }else { + shareBook.setMemberLastName(shareName); + } + LogUtil.info(BookingService.class, + "[synvBookingSharer] getshareName " + gson.toJson(shareName)); + }else { + LogUtil.info(BookingService.class, + "[synvBookingSharer] noName no PlayerId " ); + continue; + } +// shareBook.setBlockCode(null); + //25-05-24 sharer no item code + shareBook.setItemCode(null); + shareBook.setRatePlanCode("NR"); + shareBook.setPromotionCode(null); + shareBook.setMember(null); + + createSharerRequest.setBooking(shareBook); + createSharerRequest.setNumberOfUnits(0); + createSharerRequest.setNumberOfAdults(0); + + createBookResponse = operaService.createBooking(createSharerRequest); + LogUtil.info(BookingService.class, + "[synvBookingSharer] createBookResponse " + gson.toJson(createBookResponse)); + if (createBookResponse.get("internal_id") != null) { + String confirmationNo = String.valueOf(createBookResponse.get("internal_id")); + shareConfirmationNo.add(confirmationNo); + shareBook.setConfirmationNo(confirmationNo); + successShareBooks.add(shareBook); + shareObj.put("confirmation_no", confirmationNo); + dynList.set(a, shareObj); + LogUtil.info(BookingService.class, + "[synvBookingSharer] confirmationNo " + gson.toJson(confirmationNo)); + }else { + String errorMsg = "Create sharer booking failed."; + if(!StringUtils.isEmpty(shareBook.getConfirmationNo())) errorMsg+="Confirmation No:"+shareBook.getConfirmationNo()+"."; + if(!StringUtils.isEmpty(sharePlayerId)) errorMsg+="Sharer Player ID:"+sharePlayerId+"."; + if(!StringUtils.isEmpty(shareName)) errorMsg+="Sharer Name:"+shareName+"."; + if(createBookResponse.containsKey("message")) errorMsg+="Error Message:"+createBookResponse.getString("message")+"."; + shareBook.setId(null); + shareBook.setConfirmationNo(null); + shareBook.setApproveStatus("F"); + shareBook.setTryTime(5); + + shareBook.setErrorMessage(errorMsg); + bookingDao.save(shareBook); + } + } + + //loop combine share + List shareResponseList = new ArrayList(); + LogUtil.info(BookingService.class, + "[synvBookingSharer] shareConfirmationNo size " +shareConfirmationNo.size()); + if(shareConfirmationNo != null && !shareConfirmationNo.isEmpty()) { + for (String s : shareConfirmationNo) { + List confirmationNos = new ArrayList(); + confirmationNos.add(s); + combineShareRequest = new CombineShareRequest(); + combineShareRequest.setConfirmationNo(successBook.getConfirmationNo()); + combineShareRequest.setJoinConfirmationNos(confirmationNos); + LogUtil.info(BookingService.class, + "[synvBookingSharer] setJoinConfirmationNos" + gson.toJson(confirmationNos)); + combineShareRequest.setProperty(property); + JSONObject shareResponse = operaService.combineShare(combineShareRequest); + LogUtil.info(BookingService.class, + "[synvBookingSharer] shareResponse" + gson.toJson(shareResponse)); + if (shareResponse != null) shareResponseList.add(shareResponse); + } + } + booking.setSharer(JSONArray.toJSONString(dynList)); + bookingDao.save(booking); + } + return booking; + } + + public Bookings getRoomType(Bookings booking,Long roomId,Date checkinDate,Date checkoutDate,Long bedTypeMasterGroupId) throws Exception { + // -----------------根据PropertyId,RoomId,(BedTypeId可选)随机拿一个RoomTypeId----------------------- + Long roomTypeId = null; + String roomTypeCode = ""; + List roomTypes = new ArrayList(); + List bedTypes = new ArrayList(); + if(bedTypeMasterGroupId==null) { + roomTypes = roomRoomTypeDao.queryByRoomId(roomId); + if(roomTypes!=null && !roomTypes.isEmpty()) { + ArrayList failedRoomType = new ArrayList(); + for (CfgRoomsRoomTypes getRoomType : roomTypes) { + roomTypeId = getRoomType.getRoomTypeId(); + + CfgRoomTypes roomType = roomTypeDao.getById(roomTypeId); + if (roomType != null) { + roomTypeCode = roomType.getCode(); + Integer failedNum = bookingDao.checkRoomTypeFailedBooking(checkinDate, checkoutDate, roomTypeCode); + + if (failedNum > 0) { + HashMap roomTypeMap = new HashMap(); + roomTypeMap.put("num", failedNum); + roomTypeMap.put("id", roomTypeId); + roomTypeMap.put("type", roomTypeCode); + failedRoomType.add(roomTypeMap); + roomTypeId = null; + roomTypeCode = null; + continue; + } else { + break; + } + } else { + roomTypeId = null; + } + } + if(StringUtils.isEmpty(roomTypeCode)) { + if(failedRoomType != null && !failedRoomType.isEmpty()) { + HashMap getRoomType = new HashMap(); + for (Object o : failedRoomType) { + HashMap getRoomTypeMap = (HashMap) o; + if (!getRoomType.containsKey("num")) { + getRoomType = getRoomTypeMap; + } else { + int mapNum = Integer.valueOf(String.valueOf(getRoomTypeMap.get("num"))); + int typeNum = Integer.valueOf(String.valueOf(getRoomType.get("num"))); + if (mapNum < typeNum) { + getRoomType = getRoomTypeMap; + } + } + } + if(getRoomType.containsKey("id")) roomTypeId = Long.valueOf(String.valueOf(getRoomType.get("id"))); + if(getRoomType.containsKey("type")) roomTypeCode = String.valueOf(getRoomType.get("type")); + } + } + } + }else { + bedTypes = bedTypeMappingDao.queryByMasterGroupId(bedTypeMasterGroupId);// 该方法可能要改成一个view的直接拿到RoomTypeId和RoomTypeCode + if(bedTypes!=null && !bedTypes.isEmpty()) { + ArrayList failedRoomType = new ArrayList(); + for (CfgBedTypeMapping getRoomType : bedTypes) { + roomTypeId = Long.valueOf(getRoomType.getRoomTypeId()); + + CfgRoomTypes roomBedType = roomTypeDao.getById(roomTypeId); + if (roomBedType != null) { + roomTypeCode = roomBedType.getCode(); + Integer failedNum = bookingDao.checkRoomTypeFailedBooking(checkinDate, checkoutDate, roomTypeCode); + + if (failedNum > 0) { + HashMap roomTypeMap = new HashMap(); + roomTypeMap.put("num", failedNum); + roomTypeMap.put("id", roomTypeId); + roomTypeMap.put("type", roomTypeCode); + failedRoomType.add(roomTypeMap); + roomTypeId = null; + roomTypeCode = null; + continue; + } else { + break; + } + } else { + roomTypeId = null; + } + } + if(StringUtils.isEmpty(roomTypeCode)) { + if(failedRoomType != null && !failedRoomType.isEmpty()) { + HashMap getRoomType = new HashMap(); + for (Object o : failedRoomType) { + HashMap getRoomTypeMap = (HashMap) o; + if (!getRoomType.containsKey("num")) { + getRoomType = getRoomTypeMap; + } else { + int mapNum = Integer.parseInt(String.valueOf(getRoomTypeMap.get("num"))); + int typeNum = Integer.parseInt(String.valueOf(getRoomType.get("num"))); + if (mapNum < typeNum) { + getRoomType = getRoomTypeMap; + } + } + } + if(getRoomType.containsKey("id")) roomTypeId = Long.valueOf(String.valueOf(getRoomType.get("id"))); + if(getRoomType.containsKey("type")) roomTypeCode = String.valueOf(getRoomType.get("type")); + } + } + } + } + // 如果没有RoomTypeId或者RoomTypeCode就报错提示前端 + if(roomTypeId==null || StringUtils.isEmpty(roomTypeCode)) { + JSONObject exption = new JSONObject(); + exption.put("errorCode", "ROOMTYPE_CODE_NOT_FOUND"); + exption.put("errorMessage", "[BookingService][createBooking]Room type code not found. roomId="+roomId+";bedTypeMasterGroupId="+bedTypeMasterGroupId); + throw new Exception(JSONObject.toJSONString(exption)); + } + booking.setRoomTypeId(roomTypeId); + booking.setRoomTypeCode(roomTypeCode); + + return booking; + } + + public DataTableResult getBookingByPage(BookingQueryRequest queryFilter) { + Specification listSpec = buildSpecificationViewByQueryFilter(queryFilter); + int pageSize = queryFilter.getPageSize(); + int pageStart = queryFilter.getPageNo(); + String sortProperties = queryFilter.getSortOrder(); + sortProperties = Strings.CS.replace(sortProperties, "1-asc", "-asc"); + sortProperties = Strings.CS.replace(sortProperties, "1-desc", "-desc"); + Sort sort = DaoUtil.buildSortByFilter(sortProperties, "id"); + Pageable pageable = PageRequest.of(pageStart, pageSize, sort); + Page resultPage = bookingViewDao.findAll(listSpec, pageable); + DataTableResult dataResult = new DataTableResult(); + dataResult.setTotalRecords(resultPage.getTotalElements()); + dataResult.setPageSize(pageSize); + List resultList = resultPage.getContent(); + for (int i = 0; i < resultList.size(); i++) { + BookingsView res = resultList.get(i); + if (Strings.CS.contains(sortProperties, "dailyTheoProfit-asc")) { + String dataNum = resultPage.getTotalElements() - ((long) pageSize * pageStart) - i + ""; + res.setDailyTheoProfit(dataNum); + } else { + String dataNum = pageSize * pageStart + i + 1 + ""; + res.setDailyTheoProfit(dataNum); + } + Bookings getBook = bookingDao.findById(res.getId()).orElse(null); + if (getBook.getMember() == null || StringUtils.isEmpty(getBook.getMember())) { + if (!StringUtils.isEmpty(getBook.getPlayerId())) { + BaseApiResponse serviceResult = playerService.findWebPlayerProfileByPlayerId(getBook.getPlayerId()); + if (serviceResult.isSuccess()) { + PlayerProfileEntry profile = serviceResult.getData(); + getBook.setMemberLastName(profile.getName()); + getBook.setMemberTitle(profile.getSalutation()); + getBook.setMember(JSONObject.toJSONString(profile)); + bookingDao.save(getBook); + } + } + } + if (getBook.getBooker() == null || StringUtils.isEmpty(getBook.getBooker())) { + if (!StringUtils.isEmpty(getBook.getCreatedBy())) { + BaseApiResponse userInfoRes = mgmUserService.findUserInfoByUserId(getBook.getCreatedBy()); + if (userInfoRes.isSuccess()) { + UserInfoApiRecord userInfo = userInfoRes.getData(); + getBook.setBooker(userInfo.getUserName()); + getBook.setCreatedByName(userInfo.getUserName()); + bookingDao.save(getBook); + } + } + } + } + dataResult.setRowData(resultList); + return dataResult; + } + + private Specification buildSpecificationViewByQueryFilter(BookingQueryRequest queryFilter) { + Specification Bookingpec = new Specification() { + @Override + public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder cb) { + List list = new ArrayList<>(); + if (StringUtils.isNotBlank(queryFilter.getSearchName())) { + list.add(cb.like(cb.upper(root.get("id")), + "%" + queryFilter.getSearchName().toUpperCase() + "%")); + } + if (StringUtils.isNotBlank(queryFilter.getSearchType())) { + list.add(cb.like(cb.upper(root.get("bookType")), + "%" + queryFilter.getSearchType().toUpperCase() + "%")); + } + if (StringUtils.isNotBlank(queryFilter.getSearchPlayerId())) { + list.add(cb.like(cb.upper(root.get("playerId")), + "%" + queryFilter.getSearchPlayerId().toUpperCase() + "%")); + } + if (StringUtils.isNotBlank(queryFilter.getSearchBookerId())) { + list.add(cb.like(cb.upper(root.get("createdBy")), + "%" + queryFilter.getSearchBookerId().toUpperCase() + "%")); + } + if (StringUtils.isNotBlank(queryFilter.getSearchApproverName())) { + list.add(cb.like(cb.upper(root.get("approvedBy")), + "%" + queryFilter.getSearchApproverName().toUpperCase() + "%")); + } + if (StringUtils.isNotBlank(queryFilter.getSearchBookerName())) { + list.add(cb.like(cb.upper(root.get("booker")), + "%" + queryFilter.getSearchBookerName().toUpperCase() + "%")); + } + if (StringUtils.isNotBlank(queryFilter.getSearchBookerTeam())) { + list.add(cb.like(cb.upper(root.get("bookerTeam")), + "%" + queryFilter.getSearchBookerTeam().toUpperCase() + "%")); + } + if (StringUtils.isNotBlank(queryFilter.getSearchConfirmationNo())) { + list.add(cb.like(cb.upper(root.get("confirmationNo")), + "%" + queryFilter.getSearchConfirmationNo().toUpperCase() + "%")); + } + if(StringUtils.isNotBlank(queryFilter.getSearchStatus())) { + List searchStatus = DaoUtil.parseMultipleFilter(queryFilter.getSearchStatus()); + if(searchStatus.size()==1) { + list.add(cb.equal(root.get("approveStatus"), searchStatus.getFirst())); + }else if(searchStatus.size()>1) { + list.add(root.get("approveStatus").in(searchStatus)); + } + } + if (queryFilter.getSearchPropertyId()!=null) { + list.add(cb.equal(root.get("propertyId"), + queryFilter.getSearchPropertyId())); + } + if (queryFilter.getSearchBookDate()!=null && queryFilter.getSearchBookDate().size()>=2) { + List date = queryFilter.getSearchBookDate(); + list.add(cb.greaterThanOrEqualTo(root.get("createdAt"),DateTimeUtil.getDateFromString(date.get(0) + " 00:00:00", "yyyy-MM-dd HH:mm:ss") )); + list.add(cb.lessThanOrEqualTo(root.get("createdAt"), DateTimeUtil.getDateFromString(date.get(1) + " 23:59:59", "yyyy-MM-dd HH:mm:ss") )); + } + if(queryFilter.getSearchCheckInDate()!=null && !queryFilter.getSearchCheckInDate().isEmpty()){ + List date = queryFilter.getSearchCheckInDate(); + list.add(cb.greaterThanOrEqualTo(root.get("checkinDate"),DateTimeUtil.getDateFromString(date.get(0), "yyyy-MM-dd") )); + if(date.size()>1) { + list.add(cb.lessThanOrEqualTo(root.get("checkinDate"), DateTimeUtil.getDateFromString(date.get(1), "yyyy-MM-dd") )); + } + } + if (queryFilter.getSearchApproverDate()!=null && !queryFilter.getSearchApproverDate().isEmpty()) { + List date = queryFilter.getSearchApproverDate(); + list.add(cb.greaterThanOrEqualTo(root.get("approvedAt"),DateTimeUtil.getDateFromString(date.get(0)+ " 00:00:00", "yyyy-MM-dd HH:mm:ss") )); + if(date.size()>1) { + list.add(cb.lessThanOrEqualTo(root.get("approvedAt"), DateTimeUtil.getDateFromString(date.get(1)+ " 23:59:59", "yyyy-MM-dd HH:mm:ss") )); + } + } + if(StringUtils.isNotBlank(queryFilter.getPermissionId())) { + String routerId=queryFilter.getPermissionId(); + String paraGroup=queryFilter.getPermissionGroup(); + String groupName = StringUtils.isNotBlank(paraGroup)?paraGroup:"NO_GROUP"; + List accessRoomIds = sysGroupPermissionService.getGroupAccessRoomIds(routerId, groupName); + list.add(root.get("roomId").in(accessRoomIds)); + } + if(queryFilter.getSearchRoomId()!=null && !queryFilter.getSearchRoomId().isEmpty()) { + List roomIds = queryFilter.getSearchRoomId(); + if(roomIds != null && !roomIds.isEmpty()) { + list.add(root.get("roomId").in(roomIds)); + } + } + if(queryFilter.getSearchRoomTypeId()!=null && !queryFilter.getSearchRoomTypeId().isEmpty()) { + List roomTypeIds = queryFilter.getSearchRoomTypeId(); + list.add(root.get("roomTypeId").in(roomTypeIds)); + } + + Predicate[] predicates = new Predicate[list.size()]; + criteriaQuery.where(list.toArray(predicates)); + return cb.and(list.toArray(predicates)); + } + }; + return Bookingpec; + } + + //重新计算 booking allotment + public void processAllotment(Long roomId,Date checkinDate ,Date checkoutDate,Long propertyId,Long blockId) { + List roomIds = new ArrayList<>(); + roomIds.add(roomId); + Date endDate = DateTimeUtil.addDay(checkoutDate, -1); + List criterias = criteriaDao.findByRoomIdInAndPropertyIdAndBookDateBetween + (roomIds,propertyId,checkinDate,endDate); + List updateChannelList = new ArrayList<>(); + for(CfgRoomCriterias c:criterias) { + CfgAppChannel channel = new CfgAppChannel(); + Set channels = c.getChannels(); + for(CfgAppChannel a:channels) { + if(a.getBlockId()!=null&&blockId!=null) { + if(a.getBlockId().longValue()==blockId.longValue()) { + channel = a; + int pickUp = 0; + Integer appChannel = 0; + pickUp = bookingDao.getPickupBooking(propertyId, roomId, blockId, c.getBookDate()); + if(channel.getAppChannel()!=null) { + appChannel = channel.getAppChannel(); + } + channel.setPickedUp(pickUp); + channel.setAvailable(channel.getAppChannel()-channel.getPickedUp()); + updateChannelList.add(channel); + } + } + } + } + if(updateChannelList !=null && !updateChannelList.isEmpty()) appChannelDao.saveAll(updateChannelList); + } + + public List getFailedBooking() { + return bookingDao.getFailedBooking(); + } + + public int updateProcessStatus(long id) { + int res = 0; + Bookings getBook = bookingDao.findById(id).orElse(null); + if(getBook.getProcessStatus()!=1) { + res = bookingDao.updateProcessStatus(id, 1); + } + return res; + } + + public void changeStatus() { + bookingViewDao.changeDueIn(); + bookingViewDao.changeCheckedIn(); + bookingViewDao.changeDueOut(); + bookingViewDao.changeCheckedOut(); + bookingViewDao.changeNoShow(); + } + + //------------------------------ + //---- Optimize flows ---------- + + /** + * merge + * @param daylightBooking 这里是从PMS返回的数据 + * @param dbBookingView 这里是本地DB数据的数据 + * @param bookingViews PMS返回的数据提取出它们的reservationId后,通过这些id查出的对应的booking list + */ + private void mergeDaylightRowFromExistingDbBooking_Optimize(BookingDto daylightBooking, + BookingsView dbBookingView, + List bookingViews) { + daylightBooking.setMergeOperation("UPDATE"); + daylightBooking.setId(dbBookingView.getId()); + daylightBooking.setCreatedAt(dbBookingView.getCreatedAt()); + daylightBooking.setApproveStatus(dbBookingView.getApproveStatus()); + daylightBooking.setResvId(dbBookingView.getResvId()); + String nights = DateTimeUtil.getDiffDate(daylightBooking.getCheckinDate(), daylightBooking.getCheckoutDate(), "day"); + daylightBooking.setNumOfNight(Integer.valueOf(nights)); + daylightBooking.setPropertyName(dbBookingView.getPropertyName()); + daylightBooking.setPropertyId(dbBookingView.getPropertyId()); + daylightBooking.setRoomTypeId(dbBookingView.getRoomTypeId()); + daylightBooking.setMiscCharge(dbBookingView.getMiscCharge()); + + // Fill dateList when dbBookingView's dateList is null or empty + if (dbBookingView.getDateList() == null || dbBookingView.getDateList().isEmpty()) { + int dateListNumOfNight = Integer.parseInt(DateTimeUtil.getDiffDate(daylightBooking.getCheckinDate(), daylightBooking.getCheckoutDate(), "day")); + List dates = new ArrayList<>(); + for (int j = 0; j < dateListNumOfNight + 1; j++) { + dates.add(DateTimeUtil.getDateByFormat(DateTimeUtil.addDay(daylightBooking.getCheckinDate(), j), "yyyy-MM-dd")); + } + BookingDateEntry dateEntry = new BookingDateEntry(); + dateEntry.setBookingStatus(""); + dateEntry.setChecked(false); + dateEntry.setDate(dates); + dateEntry.setNumOfNight(dateListNumOfNight); + dateEntry.setNumOfRoom(1); + dateEntry.setRemark(""); + dateEntry.setStatus(0); + dateEntry.setSubmit(true); + List dateListEntries = new ArrayList<>(); + dateListEntries.add(dateEntry); + daylightBooking.setDateList(dateListEntries); + } + + // TODO get sharer from daylight + boolean isOperaShare = true; + daylightBooking.setShare(false); + + Bookings dbBooking = bookingDao.findById(dbBookingView.getId()).orElse(null); + if (dbBooking == null) { + return; + } + if (dbBooking.getMiscCharge() != null) { + daylightBooking.setMiscCharge(dbBooking.getMiscCharge()); + } + String mergedDaylightStatus = resolveDaylightLastOperaStatus( + daylightBooking.getLastOperaStatus(), dbBooking.getLastOperaStatus()); + daylightBooking.setLastOperaStatus(mergedDaylightStatus); + + // Daylight 的 RESERVED 是当前权威状态。原 booking(非 revision)若因直接延期被错误标记为 PN, + // 搜索同步时应恢复为已确认的 N;真正的 pending revision 保持 PN。 + if ("RESERVED".equalsIgnoreCase(mergedDaylightStatus) + && "PN".equalsIgnoreCase(daylightBooking.getApproveStatus()) + && dbBooking.getRevisionOf() == null) { + daylightBooking.setApproveStatus("N"); + } + + // if ("PN".equals(dbBookingView.getApproveStatus())) { + // daylightBooking.setCheckinDate(dbBookingView.getCheckinDate()); + // daylightBooking.setCheckoutDate(dbBookingView.getCheckoutDate()); + // } + CfgRoomTypes daylightRoomType = roomTypeDao.findByDlRoomTypeId(daylightBooking.getDlRoomTypeId()); + if (daylightRoomType != null) { + daylightBooking.setRoomTypeId(daylightRoomType.getId()); + daylightBooking.setRoomTypeCode(daylightRoomType.getCode()); + List roomRoomType = roomRoomTypeDao.findByRoomTypeId(daylightRoomType.getId()); + if (!roomRoomType.isEmpty()) { + for (CfgRoomsRoomTypes r : roomRoomType) { + CfgRooms room = roomDao.findById(r.getRoomId()); + if (room != null) { + if (Long.valueOf(room.getPropertyId()).equals(dbBookingView.getPropertyId())) { + daylightBooking.setRoom(room.getName()); + daylightBooking.setRoomId(room.getId()); + break; + } + } + } + } + } + resolveDaylightBlockInfo(daylightBooking); + resolveDaylightSourceCode(daylightBooking); + List operaMarketCode = marketCodeDao.findByCodeAndCategory(daylightBooking.getMarketCode(), "DAYLIGHT"); + List operRateCode = rateCodeDao.findByCodeAndCategory(daylightBooking.getRatePlanCode(), "DAYLIGHT"); + if (!operaMarketCode.isEmpty() && !operRateCode.isEmpty()) { + Long operaMarketCodeId = operaMarketCode.getFirst().getId(); + Long operaRateCodeId = operRateCode.getFirst().getId(); + List bookingTypeOperas = daylightViewDao.findByMarketCodeIdAndRateCodeId(operaMarketCodeId, operaRateCodeId); + if (!bookingTypeOperas.isEmpty()) { + Long operaBookingTypeId = bookingTypeOperas.getFirst().getBookingTypeId(); + daylightBooking.setBookingTypeId(operaBookingTypeId); + } + } + + if ("CANCELED".equals(daylightBooking.getLastOperaStatus())) { + // if (!"PN".equals(dbBookingView.getApproveStatus())) { + daylightBooking.setApproveStatus("C"); + // } + } else { + if ("C".equals(dbBookingView.getApproveStatus())) { + daylightBooking.setApproveStatus("N"); + } + } + if ("CANCELED".equals(daylightBooking.getLastOperaStatus()) + && !"CANCELED".equals(dbBookingView.getLastOperaStatus())) { + daylightBooking.setMergeOperation("CANCELED"); + if(dbBooking.getRoomId()!=null && dbBooking.getBlockId()!=null){ + //-- Set cancel info for allotment + BookingCancelInfo cancelInfo = new BookingCancelInfo(); + cancelInfo.setBookingId(dbBooking.getId()); + cancelInfo.setPropertyId(dbBooking.getPropertyId()); + cancelInfo.setRoomId(dbBooking.getRoomId()); + cancelInfo.setBlockId(dbBooking.getBlockId()); + cancelInfo.setCheckinDate(dbBooking.getCheckinDate()); + cancelInfo.setCheckoutDate(dbBooking.getCheckoutDate()); + daylightBooking.setCancelInfo(cancelInfo); + } + } + if(StringUtils.isNotBlank(dbBooking.getMember())){ + daylightBooking.setMember(JSONObject.parseObject(dbBooking.getMember(), PlayerProfileEntry.class)); + } + + if (StringUtils.isBlank(dbBooking.getMember())) { + if (StringUtils.isNotBlank(daylightBooking.getPlayerId())) { + BaseApiResponse serviceResult = playerService.findWebPlayerProfileByPlayerId(daylightBooking.getPlayerId()); + if (serviceResult.isSuccess()) { + PlayerProfileEntry profile = serviceResult.getData(); + daylightBooking.setMemberLastName(profile.getName()); + daylightBooking.setMemberTitle(profile.getSalutation()); + daylightBooking.setMember(profile); + } + } + } + // 记录 Daylight(PMS) 侧返回的创建人信息,避免被本地 DB 的空值覆盖后丢失 + String dlBooker = StringUtils.trimToNull(daylightBooking.getBooker()); + String dlCreatedBy = StringUtils.trimToNull(daylightBooking.getCreatedBy()); + + daylightBooking.setBooker(dbBooking.getBooker()); + daylightBooking.setCreatedByName(dbBooking.getCreatedByName()); + + // 优先用本地 DB 的 createdBy 解析用户名;webhook 新插入的记录本地 createdBy 为空,回退到 Daylight 返回的 createdBy + String lookupKey = StringUtils.isNotBlank(dbBooking.getCreatedBy()) + ? dbBooking.getCreatedBy() + : dlCreatedBy; + + boolean needResolve = StringUtils.isBlank(daylightBooking.getCreatedByName()) + || StringUtils.isBlank(daylightBooking.getBooker()); + + if (needResolve && StringUtils.isNotBlank(lookupKey)) { + BaseApiResponse userInfoRes = mgmUserService.findUserInfoByUserId(lookupKey); + if (userInfoRes.isSuccess()) { + UserInfoApiRecord userInfo = userInfoRes.getData(); + daylightBooking.setCreatedBy(lookupKey); + daylightBooking.setBooker(userInfo.getUserName()); + daylightBooking.setCreatedByName(userInfo.getUserName()); + daylightBooking.setSectionId(userInfo.getSectionId()); + } + } + + // 兜底:仍无创建人名称时,使用 Daylight 返回的 Booker 名称,避免返回空值 + if (StringUtils.isBlank(daylightBooking.getCreatedByName()) && dlBooker != null) { + daylightBooking.setCreatedByName(dlBooker); + if (StringUtils.isBlank(daylightBooking.getBooker())) { + daylightBooking.setBooker(dlBooker); + } + } + // 【设置字段位置 ②】Daylight 已有预订合并 — 在此设置的字段会通过 syncDaylightMergeBookingToDbAndPopulateIds_Optimize 保存到 DB + // 示例: daylightBooking.setXxx(value); + if (daylightBooking.getSectionId() == null && dbBooking.getSectionId() != null) { + daylightBooking.setSectionId(dbBooking.getSectionId()); + } + + + + int expMin = 20000; + expMin = expMin * -1; + Date dtNow = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + dtNow = DateTimeUtil.addMin(dtNow, expMin); + + Long revisionOf = 0L; + for (int k = 0; k < bookingViews.size(); k++) { + BookingsView bookingPending = bookingViews.get(k); + if (dbBooking.getId().equals(bookingPending.getRevisionOf()) + && ( "PN".equals(bookingPending.getApproveStatus()) || "W".equals(bookingPending.getApproveStatus())) + && bookingPending.getCreatedAt().getTime() >= dtNow.getTime()) { + if (bookingPending.getId() > revisionOf) { + daylightBooking.setPendingRevisionId(bookingPending.getId()); + } + revisionOf = bookingPending.getId(); + } + } + } + + public void supplementDaylightBookingRow_Optimize(BookingDto daylightBooking, PlayerProfileEntry member, String userId) throws Exception { + CfgProperties daylightProperty = propertyDao.getByDlPropertyId(daylightBooking.getDlPropertyId()); + CfgRoomTypes daylightRoomType =roomTypeDao.findByDlRoomTypeId(daylightBooking.getDlRoomTypeId()); + Long propertyId = null; + Long roomId= (long) -1; + Long roomTypeId= (long) -1; + String roomName=""; + String roomTypeCode=""; + //set room type + if(daylightRoomType!=null && daylightProperty!=null) { + propertyId = daylightProperty.getId(); + roomTypeId = daylightRoomType.getId(); + roomTypeCode = daylightRoomType.getCode(); + List roomRoomTypes = roomRoomTypeDao.findByRoomTypeId(roomTypeId); + if(!roomRoomTypes.isEmpty()) { + for(CfgRoomsRoomTypes r:roomRoomTypes) { + CfgRooms room = roomDao.findById(r.getRoomId()); + if(room!=null) { + if(Long.valueOf(room.getPropertyId()).equals(propertyId)) { + roomId = room.getId(); + roomName = room.getName(); + break; + } + } + } + } + } + resolveDaylightBlockInfo(daylightBooking); + resolveDaylightSourceCode(daylightBooking); + String operaMemberTitle = ""; + String operaMemberFirstName = ""; + String operaMemberLastName = ""; + String playerId = member.getPlayerId(); + daylightBooking.setPlayerId(playerId); + daylightBooking.setPropertyId(propertyId); + daylightBooking.setPropertyName(daylightProperty != null ? daylightProperty.getName() : null); + daylightBooking.setNotifyLanguage("en"); + + daylightBooking.setRoom(roomName); + daylightBooking.setRoomId(roomId); + daylightBooking.setRoomTypeId(roomTypeId); + daylightBooking.setChainCode(daylightProperty!=null?daylightProperty.getCode():null); + daylightBooking.setRoomTypeCode(roomTypeCode); + daylightBooking.setCreatedByName(daylightBooking.getCreatedBy()); + daylightBooking.setUpdatedBy(userId); + + daylightBooking.setMemberTitle(operaMemberTitle); + daylightBooking.setMemberFirstName(operaMemberFirstName); + daylightBooking.setMemberLastName(operaMemberLastName); + daylightBooking.setApproveStatus("N"); + daylightBooking.setCreatedAt(daylightBooking.getDataTime()); + daylightBooking.setUpdatedAt(daylightBooking.getDataTime()); + daylightBooking.setSharer(new JSONArray().toJSONString()); + daylightBooking.setSharerList(new JSONArray()); + daylightBooking.setBookType("0"); + //get player info + if(!StringUtils.isEmpty(daylightBooking.getPlayerId())) { + BaseApiResponse serviceResult = playerService.findWebPlayerProfileByPlayerId(daylightBooking.getPlayerId()); + if(serviceResult.isSuccess()) { + PlayerProfileEntry profile = serviceResult.getData(); + daylightBooking.setMemberLastName(profile.getName()); + daylightBooking.setMemberTitle(profile.getSalutation()); + daylightBooking.setMember(profile); + } + } + //get user info + if(!StringUtils.isEmpty(daylightBooking.getCreatedBy())) { + BaseApiResponse userInfoRes = mgmUserService.findUserInfoByUserId(daylightBooking.getCreatedBy()); + if(userInfoRes.isSuccess()) { + UserInfoApiRecord userInfo = userInfoRes.getData(); + daylightBooking.setBooker(userInfo.getUserName()); + daylightBooking.setCreatedByName(userInfo.getUserName()); + daylightBooking.setSectionId(userInfo.getSectionId()); + } + } + //get Booking Type + List operaMarketCode = marketCodeDao.findByCodeAndCategory(daylightBooking.getMarketCode(), "DAYLIGHT"); + List operRateCode = rateCodeDao.findByCodeAndCategory(daylightBooking.getRatePlanCode(), "DAYLIGHT"); + if(!operaMarketCode.isEmpty() && !operRateCode.isEmpty()) { + Long operaMarketCodeId = operaMarketCode.getFirst().getId(); + Long operaRateCodeId = operRateCode.getFirst().getId(); + List bookingTypeOperas = daylightViewDao.findByMarketCodeIdAndRateCodeId(operaMarketCodeId,operaRateCodeId); + if(!bookingTypeOperas.isEmpty()) { + Long daylightBookingTypeId = bookingTypeOperas.getFirst().getBookingTypeId(); + daylightBooking.setBookingTypeId(daylightBookingTypeId); + } + } + // build datelist + int numOfNight = Integer.parseInt(DateTimeUtil.getDiffDate(daylightBooking.getCheckinDate(), daylightBooking.getCheckoutDate(), "day")); + List dates = new ArrayList<>(); + List dateList = new ArrayList<>(); + BookingDateEntry obj = new BookingDateEntry(); + for(int j=0;j mergeDaylightRecordFromDB_Optimize(List pmsResult, PlayerProfileEntry member, String userId) throws Exception { + Set skippedCanceledDaylightBookings = Collections.newSetFromMap(new IdentityHashMap<>()); + List bookingsForReservationFallback = new ArrayList<>(); + + // ========== Pass 1: Match by dlExternalNo ========== + LinkedHashSet dlExternalNoSet = new LinkedHashSet<>(); + for (BookingDto dlBooking : pmsResult) { + if (StringUtils.isNotBlank(dlBooking.getDlExternalNo())) { + dlExternalNoSet.add(dlBooking.getDlExternalNo().trim()); + } else { + bookingsForReservationFallback.add(dlBooking); + } + } + + List dlExternalNos = new ArrayList<>(dlExternalNoSet); + List dbBookingViews = !dlExternalNos.isEmpty() ? bookingViewDao.findByDlExternalNoIn(dlExternalNos) : new ArrayList<>(); + Map existDlExternalNoDbBookingMap = new HashMap<>(); + for (BookingsView dbBooking : dbBookingViews) { + if (StringUtils.isNotBlank(dbBooking.getDlExternalNo())) { + existDlExternalNoDbBookingMap.put(dbBooking.getDlExternalNo().trim(), dbBooking); + } + } + + for (BookingDto daylightBooking : pmsResult) { + if (StringUtils.isBlank(daylightBooking.getDlExternalNo())) { + continue; + } + boolean bookingExist = false; + BookingsView matchDbBooking = null; + String dlExternalNo = daylightBooking.getDlExternalNo().trim(); + if (existDlExternalNoDbBookingMap.containsKey(dlExternalNo)) { + bookingExist = true; + matchDbBooking = existDlExternalNoDbBookingMap.get(dlExternalNo); + } else { + Bookings existingDaylightBooking = bookingDao.getByDlExternalNo(dlExternalNo); + if (existingDaylightBooking != null) { + bookingExist = true; + matchDbBooking = toDaylightMergeBookingView(existingDaylightBooking); + dbBookingViews.add(matchDbBooking); + } + } + if (bookingExist && matchDbBooking != null) { + mergeDaylightRowFromExistingDbBooking_Optimize(daylightBooking, matchDbBooking, dbBookingViews); + } else if (isCanceledDaylightBooking(daylightBooking)) { + skippedCanceledDaylightBookings.add(daylightBooking); + } else if (StringUtils.isNotBlank(daylightBooking.getDlReservationId())) { + bookingsForReservationFallback.add(daylightBooking); + } else if (isLocalCanceledBooking(daylightBooking)) { + skippedCanceledDaylightBookings.add(daylightBooking); + } else { + supplementDaylightBookingRow_Optimize(daylightBooking, member, userId); + } + } + + // ========== Pass 2: Fallback match by dlReservationId ========== + LinkedHashSet dlIdSet = new LinkedHashSet<>(); + for (BookingDto dlBooking : bookingsForReservationFallback) { + if (StringUtils.isNotBlank(dlBooking.getDlReservationId())) { + dlIdSet.add(dlBooking.getDlReservationId().trim()); + } + } + + List dlReservationIds = new ArrayList<>(dlIdSet); + List reservationDbBookingViews = !dlReservationIds.isEmpty() ? bookingViewDao.findByDlReservationIdIn(dlReservationIds) : new ArrayList<>(); + Map existDlReservationDbBookingMap = new HashMap<>(); + for (BookingsView dbBooking : reservationDbBookingViews) { + if (StringUtils.isNotBlank(dbBooking.getDlReservationId())) { + existDlReservationDbBookingMap.put(dbBooking.getDlReservationId().trim(), dbBooking); + } + } + + for (BookingDto daylightBooking : bookingsForReservationFallback) { + boolean bookingExist = false; + BookingsView matchDbBooking = null; + if (StringUtils.isNotBlank(daylightBooking.getDlReservationId())) { + String dlReservationId = daylightBooking.getDlReservationId().trim(); + if (existDlReservationDbBookingMap.containsKey(dlReservationId)) { + bookingExist = true; + matchDbBooking = existDlReservationDbBookingMap.get(dlReservationId); + } + } + if (bookingExist && matchDbBooking != null) { + // Backfill dlExternalNo to DB record if missing + if (StringUtils.isBlank(matchDbBooking.getDlExternalNo()) && StringUtils.isNotBlank(daylightBooking.getDlExternalNo())) { + matchDbBooking.setDlExternalNo(daylightBooking.getDlExternalNo().trim()); + } + mergeDaylightRowFromExistingDbBooking_Optimize(daylightBooking, matchDbBooking, reservationDbBookingViews); + } else if (isCanceledDaylightBooking(daylightBooking)) { + skippedCanceledDaylightBookings.add(daylightBooking); + } else if (isLocalCanceledBooking(daylightBooking)) { + skippedCanceledDaylightBookings.add(daylightBooking); + } else { + supplementDaylightBookingRow_Optimize(daylightBooking, member, userId); + } + } + + if (skippedCanceledDaylightBookings.isEmpty()) { + return pmsResult; + } + List mergeableResults = new ArrayList<>(); + for (BookingDto daylightBooking : pmsResult) { + if (!skippedCanceledDaylightBookings.contains(daylightBooking)) { + mergeableResults.add(daylightBooking); + } + } + return mergeableResults; + } + + private void resolveDaylightBlockInfo(BookingDto daylightBooking) { + if (StringUtils.isBlank(daylightBooking.getDlBlockId())) { + return; + } + CfgBlockCodes blockCode = blockCodeDao.findByDlBlockId(daylightBooking.getDlBlockId()); + if (blockCode == null) { + return; + } + daylightBooking.setBlockCode(blockCode.getCode()); + if (blockCode.getBlockId() != null) { + daylightBooking.setBlockId(blockCode.getBlockId()); + } + } + + private void resolveDaylightSourceCode(BookingDto daylightBooking) { + if (StringUtils.isBlank(daylightBooking.getDlSourceId())) { + return; + } + CfgSourceCodes sourceCode = sourceCodeDao.findByDlSourceId(daylightBooking.getDlSourceId()); + if (sourceCode == null) { + return; + } + daylightBooking.setSourceCode(sourceCode.getCode()); + } + + private boolean isCanceledDaylightBooking(BookingDto daylightBooking) { + if (daylightBooking == null || daylightBooking.getLastOperaStatus() == null) { + return false; + } + return daylightBooking.getLastOperaStatus().trim().toUpperCase().contains("CANCEL"); + } + + private boolean isLocalCanceledBooking(BookingDto daylightBooking) { + if (StringUtils.isBlank(daylightBooking.getConfirmationNo())) { + return false; + } + List existingBookings = bookingViewDao.findByConfirmationNo(daylightBooking.getConfirmationNo().trim()); + if (existingBookings == null || existingBookings.isEmpty()) { + return false; + } + for (BookingsView bv : existingBookings) { + if (bv.getLastOperaStatus() != null && bv.getLastOperaStatus().trim().toUpperCase().contains("CANCEL")) { + return true; + } + } + return false; + } + + private BookingsView toDaylightMergeBookingView(Bookings booking) { + BookingsView view = new BookingsView(); + view.setId(booking.getId()); + view.setRevisionOf(booking.getRevisionOf()); + view.setConfirmationNo(booking.getConfirmationNo()); + view.setResvId(booking.getResvId()); + view.setLastOperaStatus(booking.getLastOperaStatus()); + view.setPlayerId(booking.getPlayerId()); + view.setMemberTitle(booking.getMemberTitle()); + view.setMemberFirstName(booking.getMemberFirstName()); + view.setMemberLastName(booking.getMemberLastName()); + view.setCheckinDate(booking.getCheckinDate()); + view.setCheckoutDate(booking.getCheckoutDate()); + view.setHotelCode(booking.getHotelCode()); + view.setDlProfileId(booking.getDlProfileId()); + view.setDlGuaranteeTypeId(booking.getDlGuaranteeTypeId()); + view.setDlSourceId(booking.getDlSourceId()); + view.setDlBlockId(booking.getDlBlockId()); + view.setDlChannelId(booking.getDlChannelId()); + view.setDlAccountId(booking.getDlAccountId()); + view.setDlReservationId(booking.getDlReservationId()); + view.setDlExternalNo(booking.getDlExternalNo()); + view.setPropertyId(booking.getPropertyId()); + view.setSectionId(booking.getSectionId()); + view.setBookingTypeId(booking.getBookingTypeId() != null ? booking.getBookingTypeId().intValue() : null); + return view; + } + + @Transactional + public List mergeOperaRowFromExistDbBooking_Optimize(List result, PlayerProfileEntry member, String userId) throws Exception { + List confirmationNos = new ArrayList<>(); + for (BookingDto operaBooking:result) { + if(StringUtils.isNotBlank(operaBooking.getConfirmationNo())){ + confirmationNos.add(operaBooking.getConfirmationNo()); + } + } + List dbBookingViews = !confirmationNos.isEmpty()?bookingViewDao.findByConfirmationNoIn(confirmationNos): new ArrayList(); +// LogUtil.info(getClass(), "[mergeOpera] confirmationNos=" + confirmationNos + ", dbBookingViews.size=" + dbBookingViews.size()); +// for (BookingsView bv : dbBookingViews) { +// LogUtil.info(getClass(), "[mergeOpera] DB record: id=" + bv.getId() + ", confNo=" + bv.getConfirmationNo() +// + ", hotelCode=" + bv.getHotelCode() + ", approveStatus=" + bv.getApproveStatus() + ", revisionOf=" + bv.getRevisionOf()); +// } + + for (BookingDto operaBooking:result) { + boolean bookingExist = false; + if(StringUtils.isNotBlank(operaBooking.getConfirmationNo()) && StringUtils.isNotBlank(operaBooking.getHotelCode())){ + for (BookingsView dbBookingView: dbBookingViews) { + String status = dbBookingView.getApproveStatus(); + if (status != null && status.contains("W")) { + continue; + } + if (status != null && status.contains("AP")) { + continue; + } + if (operaBooking.getConfirmationNo() == null) { + continue; + } + if (operaBooking.getConfirmationNo().equals(dbBookingView.getConfirmationNo()) && + (operaBooking.getHotelCode().equals(dbBookingView.getHotelCode()))) { + Bookings dbBooking = bookingDao.findById(dbBookingView.getId()).orElse(null); + if (dbBooking != null) { + bookingExist = true; + LogUtil.info(getClass(), "[mergeOpera] MATCHED: operaConfNo=" + operaBooking.getConfirmationNo() + + ", hotelCode=" + operaBooking.getHotelCode() + ", dbId=" + dbBooking.getId() + + ", dbApproveStatus=" + dbBooking.getApproveStatus()); + operaBooking.setId(dbBooking.getId()); + operaBooking.setCreatedAt(dbBooking.getCreatedAt()); + if(StringUtils.isBlank(operaBooking.getCreatedBy())){ + operaBooking.setCreatedBy(dbBooking.getCreatedBy()); + } + operaBooking.setApproveStatus(dbBooking.getApproveStatus()); + operaBooking.setResvId(dbBooking.getResvId()); + operaBooking.setMiscCharge(dbBooking.getMiscCharge()); + String nights = DateTimeUtil.getDiffDate(operaBooking.getCheckinDate(), operaBooking.getCheckoutDate(), "day"); + operaBooking.setNumOfNight(Integer.valueOf(nights)); + operaBooking.setPropertyName(dbBookingView.getPropertyName()); + operaBooking.setSharer(dbBooking.getSharer()); + boolean isOperaShare = true; + isOperaShare = this.checkRoomNo(dbBooking.getId(), + DateTimeUtil.getDateByFormat(dbBooking.getCheckinDate(), "yyyy-MM-dd"), + DateTimeUtil.getDateByFormat(dbBooking.getCheckoutDate(), "yyyy-MM-dd")); + operaBooking.setShare(!isOperaShare); + if ("PN".equals(dbBooking.getApproveStatus())) { + operaBooking.setCheckinDate(dbBooking.getCheckinDate()); + operaBooking.setCheckoutDate(dbBooking.getCheckoutDate()); + } + if (operaBooking.getBlockId() != null) { + List blockCodes = blockCodeDao.findByCode(operaBooking.getHotelCode()); + if (!blockCodes.isEmpty()) { + Long operaBlockId = blockCodes.getFirst().getBlockId(); + if (operaBlockId != null) { + operaBooking.setBlockId(operaBlockId); + } + } + } + //get room type code + CfgRoomTypes operRoomType = roomTypeDao.findByCodeAndCategory(operaBooking.getRoomTypeCode(), operaBooking.getPropertyCategory()); + if (operRoomType != null) { + operaBooking.setRoomTypeId(operRoomType.getId()); + operaBooking.setRoomTypeCode(operaBooking.getRoomTypeCode()); + List roomroomType = roomRoomTypeDao.findByRoomTypeId(operRoomType.getId()); + if (!roomroomType.isEmpty()) { + for (CfgRoomsRoomTypes r : roomroomType) { + CfgRooms room = roomDao.findById(r.getRoomId()); + if (room != null) { + if (Long.valueOf(room.getPropertyId()).equals(dbBooking.getPropertyId())) { + operaBooking.setRoom(room.getName()); + operaBooking.setRoomId(room.getId()); + break; + } + } + } + } + } + //get Booking Type + List operaMarketCode = marketCodeDao.findByCodeAndCategory(operaBooking.getMarketCode(), "OPERA"); + List operRateCode = rateCodeDao.findByCodeAndCategory(operaBooking.getRatePlanCode(), "OPERA"); + if (!operaMarketCode.isEmpty() && !operRateCode.isEmpty()) { + Long operaMarketCodeId = operaMarketCode.getFirst().getId(); + Long operaRateCodeId = operRateCode.getFirst().getId(); + List bookingTypeOperas = operaViewDao.findByMarketCodeIdAndRateCodeId(operaMarketCodeId, operaRateCodeId); + if (!bookingTypeOperas.isEmpty()) { + Long operaBookingTypeId = bookingTypeOperas.getFirst().getBookingTypeId(); + operaBooking.setBookingTypeId(operaBookingTypeId); + } + } + if ("CANCELED".equals(operaBooking.getLastOperaStatus())) { + operaBooking.setApproveStatus("C"); + } else { + if ("C".equals(dbBooking.getApproveStatus())) { + operaBooking.setApproveStatus("N"); + } + } + //Opera cancel booking need to increase app channel + if ("CANCELED".equals(operaBooking.getLastOperaStatus()) && + !"CANCELED".equals(dbBooking.getLastOperaStatus())) { + operaBooking.setMergeOperation("CANCELED"); + if (dbBooking.getRoomId() != null && dbBooking.getBlockId() != null) { + //-- Set cancel info for allotment + BookingCancelInfo cancelInfo = new BookingCancelInfo(); + cancelInfo.setBookingId(dbBooking.getId()); + cancelInfo.setPropertyId(dbBooking.getPropertyId()); + cancelInfo.setRoomId(dbBooking.getRoomId()); + cancelInfo.setBlockId(dbBooking.getBlockId()); + cancelInfo.setCheckinDate(dbBooking.getCheckinDate()); + cancelInfo.setCheckoutDate(dbBooking.getCheckoutDate()); + operaBooking.setCancelInfo(cancelInfo); + } + }else{ + operaBooking.setMergeOperation("UPDATE"); + } + // Copy member info from DB record + if(StringUtils.isNotBlank(dbBooking.getMember())){ + operaBooking.setMember(JSONObject.parseObject(dbBooking.getMember(), PlayerProfileEntry.class)); + } + operaBooking.setPlayerId(dbBooking.getPlayerId()); + operaBooking.setMemberLastName(dbBooking.getMemberLastName()); + operaBooking.setMemberTitle(dbBooking.getMemberTitle()); + operaBooking.setBooker(dbBooking.getBooker()); + //get player info + if (StringUtils.isBlank(dbBooking.getMember())) { + if (!StringUtils.isEmpty(operaBooking.getPlayerId())) { + + BaseApiResponse serviceResult = playerService.findWebPlayerProfileByPlayerId(operaBooking.getPlayerId()); + if (serviceResult.isSuccess()) { + PlayerProfileEntry profile = serviceResult.getData(); + operaBooking.setMemberLastName(profile.getName()); + operaBooking.setMemberTitle(profile.getSalutation()); + operaBooking.setMember(profile); + } + } + } + //get user info + operaBooking.setCreatedByName(dbBooking.getCreatedByName()); + boolean getUser = false; + String booker = StringUtils.trim(operaBooking.getBooker()); + if (booker == null || StringUtils.isEmpty(booker)) getUser = true; + if (StringUtils.isBlank(operaBooking.getCreatedByName())) getUser = true; + if (!Strings.CS.equals(dbBooking.getCreatedBy(), operaBooking.getCreatedBy())) { + getUser = true; + } + if (getUser) { + if (!StringUtils.isEmpty(operaBooking.getCreatedBy())) { + BaseApiResponse userInfoRes = mgmUserService.findUserInfoByUserId(operaBooking.getCreatedBy()); + if (userInfoRes.isSuccess()) { + UserInfoApiRecord userInfo = userInfoRes.getData(); + operaBooking.setBooker(userInfo.getUserName()); + operaBooking.setCreatedByName(userInfo.getUserName()); + operaBooking.setSectionId(userInfo.getSectionId()); + } + } + } + // 【设置字段位置 ③】Opera 已有预订合并 — 在此设置的字段会通过 syncMergeBookingToDb_Optimize 保存到 DB + // 示例: operaBooking.setXxx(value); + int expMin = 20000; + expMin = expMin * -1; + Date dtNow = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + dtNow = DateTimeUtil.addMin(dtNow, expMin); + + Long revisionOf = (long) 0; + for (int k = 0; k < dbBookingViews.size(); k++) { + BookingsView bookingPending = dbBookingViews.get(k); + if (operaBooking.getId().equals(bookingPending.getRevisionOf()) + && ("PN".equals(bookingPending.getApproveStatus()) || "W".equals(bookingPending.getApproveStatus())) + && bookingPending.getCreatedAt().getTime() >= dtNow.getTime()) { + if (bookingPending.getId() > revisionOf) { + operaBooking.setPendingRevisionId(bookingPending.getId()); + } + revisionOf = bookingPending.getId(); + } + } + } + } + } + } + //supplement opera booking in records + if (!bookingExist) { + LogUtil.info(getClass(), "[mergeOpera] NO MATCH, calling supplement: confNo=" + operaBooking.getConfirmationNo() + + ", hotelCode=" + operaBooking.getHotelCode() + ", propertyCategory=" + operaBooking.getPropertyCategory()); + this.supplementOperaBookingRow_Optimize(operaBooking,member,userId); + LogUtil.info(getClass(), "[mergeOpera] after supplement: id=" + operaBooking.getId() + + ", propertyId=" + operaBooking.getPropertyId() + ", roomTypeId=" + operaBooking.getRoomTypeId()); + } + } + return result; + } + + public void supplementOperaBookingRow_Optimize(BookingDto operaBooking, PlayerProfileEntry member, String userId) throws Exception { + CfgProperties operaProperty = propertyDao.findByHotelCode(operaBooking.getHotelCode()); + if (operaProperty == null) return; + CfgRoomTypes operRoomType =roomTypeDao.findByCodeAndCategory(operaBooking.getRoomTypeCode(),operaBooking.getPropertyCategory()); + Long propertyId =null; + Long roomTypeId =(long)-1; + Long roomId = (long)-1; + String roomName =""; + //set room type + if(operRoomType!=null) { + roomTypeId = operRoomType.getId(); + List roomRoomTypes = roomRoomTypeDao.findByRoomTypeId(roomTypeId); + if(!roomRoomTypes.isEmpty()) { + for(CfgRoomsRoomTypes r:roomRoomTypes) { + CfgRooms room = roomDao.findById(r.getRoomId()); + if(room!=null) { + if(Long.valueOf(room.getPropertyId()).equals(operaProperty.getId())) { + roomId = room.getId(); + roomName = room.getName(); + break; + } + } + } + } + } + String operaMemberTitle = ""; + String operaMemberFirstName = ""; + String operaMemberLastName = ""; + String playerId=member.getPlayerId(); + operaBooking.setPlayerId(playerId); + operaBooking.setPropertyId(operaProperty.getId()); + operaBooking.setPropertyName(operaProperty.getName()); + operaBooking.setNotifyLanguage("en"); + operaBooking.setRoom(roomName); + operaBooking.setRoomId(roomId); + operaBooking.setRoomTypeId(roomTypeId); +// operaBooking.setChainCode(operaProperty.getCode()); + operaBooking.setCreatedByName(operaBooking.getCreatedBy()); + operaBooking.setUpdatedBy(userId); + operaBooking.setMemberTitle(operaMemberTitle); + operaBooking.setMemberFirstName(operaMemberFirstName); + operaBooking.setMemberLastName(operaMemberLastName); + operaBooking.setPaymentType(null); + operaBooking.setApproveStatus("N"); + operaBooking.setCreatedAt(operaBooking.getDataTime()); + operaBooking.setUpdatedAt(operaBooking.getDataTime()); + operaBooking.setSharer(new JSONArray().toJSONString()); + operaBooking.setSharerList(new JSONArray()); + operaBooking.setBookType("0"); + //get player info + if(!StringUtils.isEmpty(operaBooking.getPlayerId())) { + + BaseApiResponse serviceResult = playerService.findWebPlayerProfileByPlayerId(operaBooking.getPlayerId()); + if(serviceResult.isSuccess()) { + PlayerProfileEntry profile = serviceResult.getData(); + operaBooking.setMemberLastName(profile.getName()); + operaBooking.setMemberTitle(profile.getSalutation()); + operaBooking.setMember(profile); + } + } + //get user info + if(!StringUtils.isEmpty(operaBooking.getCreatedBy())) { + + BaseApiResponse userInfoRes = mgmUserService.findUserInfoByUserId(operaBooking.getCreatedBy()); + if(userInfoRes.isSuccess()) { + UserInfoApiRecord userInfo = userInfoRes.getData(); + operaBooking.setBooker(userInfo.getUserName()); + operaBooking.setCreatedByName(userInfo.getUserName()); + operaBooking.setSectionId(userInfo.getSectionId()); + } + } + + //get Booking Type + List operaMarketCode = marketCodeDao.findByCodeAndCategory(operaBooking.getMarketCode(), "OPERA"); + List operRateCode = rateCodeDao.findByCodeAndCategory(operaBooking.getRatePlanCode(), "OPERA"); + if(!operaMarketCode.isEmpty() && !operRateCode.isEmpty()) { + Long operaMarketCodeId = operaMarketCode.getFirst().getId(); + Long operaRateCodeId = operRateCode.getFirst().getId(); + List bookingTypeOperas = operaViewDao.findByMarketCodeIdAndRateCodeId(operaMarketCodeId,operaRateCodeId); + if(!bookingTypeOperas.isEmpty()) { + Long operaBookingTypeId = bookingTypeOperas.getFirst().getBookingTypeId(); + operaBooking.setBookingTypeId(operaBookingTypeId); + } + } + // build datelist + int numOfNight = Integer.parseInt(DateTimeUtil.getDiffDate(operaBooking.getCheckinDate(), operaBooking.getCheckoutDate(), "day")); + List dates = new ArrayList<>(); + List dateList = new ArrayList<>(); + BookingDateEntry obj = new BookingDateEntry(); + for(int j=0;j mergedBookingDtoList) { + if(mergedBookingDtoList!=null && !mergedBookingDtoList.isEmpty()){ + LogUtil.info(getClass(), "[syncMergeBooking] total bookings to sync=" + mergedBookingDtoList.size()); + for (BookingDto dto : mergedBookingDtoList) { +// LogUtil.info(getClass(), "[syncMergeBooking] id=" + dto.getId() + ", confNo=" + dto.getConfirmationNo() +// + ", hotelCode=" + dto.getHotelCode() + ", dlReservationId=" + dto.getDlReservationId() +// + ", approveStatus=" + dto.getApproveStatus() + ", lastOperaStatus=" + dto.getLastOperaStatus()); + } + if(ctrlMsgSender!=null && SysCommon.jmsRunning) { + ctrlMsgSender.sendMessage("SYNC_MERGE_BOOKING", mergedBookingDtoList); + }else { + this.updateMergeBookingToDb_Optimize(mergedBookingDtoList); + } + } + } + + @Transactional + public List syncDaylightMergeBookingToDbAndPopulateIds_Optimize(List mergedBookingDtoList) { + updateMergeBookingToDb_Optimize(mergedBookingDtoList, true); + return mergedBookingDtoList; + } + + @Async + public void updateMergeBookingToDb_Optimize(List mergedBookingDtoList){ + updateMergeBookingToDb_Optimize(mergedBookingDtoList, false); + } + + private void updateMergeBookingToDb_Optimize(List mergedBookingDtoList, boolean populateIds) { + // 1. 提前返回,减少代码嵌套层级 + if (mergedBookingDtoList == null || mergedBookingDtoList.isEmpty()) { + return; + } + + for (BookingDto mergeBookingDto : mergedBookingDtoList) { + Long existBookingId = mergeBookingDto.getId(); + + // 2. 如果 DTO 没有 ID,尝试从数据库匹配获取 ID + // 优先级: dlExternalNo > confirmationNo + if (existBookingId == null && StringUtils.isNotBlank(mergeBookingDto.getDlExternalNo())) { + Bookings matched = bookingDao.getByDlExternalNo(mergeBookingDto.getDlExternalNo().trim()); + if (matched != null) { + existBookingId = matched.getId(); + } + } + if (existBookingId == null && StringUtils.isNotBlank(mergeBookingDto.getConfirmationNo())) { + List matchBookings = bookingViewDao.findByConfirmationNo(mergeBookingDto.getConfirmationNo()); + if (matchBookings != null && !matchBookings.isEmpty()) { + existBookingId = matchBookings.getFirst().getId(); + } + } + + // 将 DTO 转换为实体 + Bookings mergedBooking = bookingMapper.dtoToBooking(mergeBookingDto); + + // 3. 根据是否拿到 existBookingId 走 更新(Update) 还是 插入(Insert) + if (existBookingId != null) { + // -- Update record + Bookings currentBooking = bookingDao.findById(existBookingId).orElse(null); + if (currentBooking == null) { + LogUtil.warn(getClass(), "Merge update is ignored as booking record does not exist. bookingId=" + existBookingId); + continue; // 找不到记录直接跳过当前循环 + } + + if ("N".equalsIgnoreCase(currentBooking.getApproveStatus())) { + insertCommentAndMiscChargeFromDaylight(mergeBookingDto); + mergedBooking.setOperaComment(mergeBookingDto.getOperaComment()); + mergedBooking.setMiscCharge(mergeBookingDto.getMiscCharge()); + } + + fillMissingMergeFieldsFromExistingBooking(mergedBooking, currentBooking); + preserveDateListDepositFields(mergedBooking, currentBooking); + mergedBooking.setId(existBookingId); + mergedBooking.setUpdatedAt(mergeBookingDto.getDataTime()); + Bookings savedBooking = bookingDao.save(mergedBooking); + + if (populateIds) { + mergeBookingDto.setId(savedBooking.getId()); + if (savedBooking.getSectionId() != null) { + mergeBookingDto.setSectionId(savedBooking.getSectionId()); + } + } + + // -- 处理取消逻辑以调整 allotment + if ("CANCELED".equalsIgnoreCase(mergeBookingDto.getMergeOperation()) && mergeBookingDto.getCancelInfo() != null) { + BookingCancelInfo cancelInfo = mergeBookingDto.getCancelInfo(); + this.processAllotment(cancelInfo.getRoomId(), + cancelInfo.getCheckinDate(), + cancelInfo.getCheckoutDate(), + cancelInfo.getPropertyId(), + cancelInfo.getBlockId()); + } + } else { + // -- Insert record + if (mergedBooking.getPropertyId() == null) { + LogUtil.warn(getClass(), "Merge insert skipped because property_id is null. confirmationNo=" + + mergeBookingDto.getConfirmationNo() + ", dlExternalNo=" + mergeBookingDto.getDlExternalNo()); + continue; + } + mergedBooking.setId(null); + String category = StringUtils.isNotBlank(mergeBookingDto.getPropertyCategory()) + ? mergeBookingDto.getPropertyCategory() : "DAYLIGHT"; + mergedBooking.setCategory(category); + if (StringUtils.isBlank(mergedBooking.getApproveStatus())) { + mergedBooking.setApproveStatus("N"); + } + mergedBooking.setCreatedAt(mergeBookingDto.getDataTime()); + mergedBooking.setUpdatedAt(mergeBookingDto.getDataTime()); + + insertCommentAndMiscChargeFromDaylight(mergeBookingDto); + mergedBooking.setOperaComment(mergeBookingDto.getOperaComment()); + mergedBooking.setMiscCharge(mergeBookingDto.getMiscCharge()); + + Bookings savedBooking = bookingDao.save(mergedBooking); + + if (populateIds) { + mergeBookingDto.setId(savedBooking.getId()); + if (savedBooking.getSectionId() != null) { + mergeBookingDto.setSectionId(savedBooking.getSectionId()); + } + } + } + } + } + + private void fillMissingMergeFieldsFromExistingBooking(Bookings mergedBooking, Bookings existingBooking) { + if (mergedBooking == null || existingBooking == null) { + return; + } + for (Field field : Bookings.class.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers()) + || field.getAnnotation(Transient.class) != null) { + continue; + } + try { + field.setAccessible(true); + Object mergedValue = field.get(mergedBooking); + if (isMissingMergeValue(mergedValue)) { + field.set(mergedBooking, field.get(existingBooking)); + } + } catch (IllegalAccessException e) { + LogUtil.warn(getClass(), "Unable to preserve existing booking field during merge: " + field.getName()); + } + } + } + + private boolean isMissingMergeValue(Object value) { + if (value == null) { + return true; + } + return value instanceof String && "null".equalsIgnoreCase(StringUtils.trim((String) value)); + } + + /** + * 保留现有 DB dateList 中的 isPost 和 depositType 字段到 merged booking 的 dateList。 + * Daylight 返回的数据不包含这两个字段,需要从本地 DB 保留。 + */ + private void preserveDateListDepositFields(Bookings mergedBooking, Bookings existingBooking) { + if (mergedBooking == null || existingBooking == null) { + return; + } + String mergedDateListStr = mergedBooking.getDateList(); + String existingDateListStr = existingBooking.getDateList(); + if (StringUtils.isBlank(mergedDateListStr) || StringUtils.isBlank(existingDateListStr)) { + return; + } + try { + JSONArray mergedArray = JSONArray.parseArray(mergedDateListStr); + JSONArray existingArray = JSONArray.parseArray(existingDateListStr); + if (mergedArray == null || existingArray == null || existingArray.isEmpty()) { + return; + } + boolean modified = false; + for (int i = 0; i < mergedArray.size() && i < existingArray.size(); i++) { + JSONObject mergedObj = mergedArray.getJSONObject(i); + JSONObject existingObj = existingArray.getJSONObject(i); + if (!mergedObj.containsKey("isPost") && existingObj.containsKey("isPost")) { + mergedObj.put("isPost", existingObj.get("isPost")); + modified = true; + } + if (!mergedObj.containsKey("depositType") && existingObj.containsKey("depositType")) { + mergedObj.put("depositType", existingObj.get("depositType")); + modified = true; + } + } + if (modified) { + mergedBooking.setDateList(mergedArray.toJSONString()); + } + } catch (Exception e) { + LogUtil.warn(getClass(), "Failed to preserve dateList deposit fields: " + e.getMessage()); + } + } + + public List getSearchRecordPending_Optimize(String checkinDate, + String checkoutDate, String playerId) { + boolean isMock = sysSettingService.isAPPMock(); + int expMin = 20000; + expMin = expMin * -1; + + Date dtNow = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + dtNow = DateTimeUtil.addMin(dtNow, expMin); + String nowStr = DateTimeUtil.getDateByFormat(dtNow, "yyyy-MM-dd HH:mm:ss"); + + return bookingMapper.viewToBookingDtoList(bookingViewDao.findRecordSearchPending(playerId, checkinDate, + checkoutDate, nowStr)); + } + + public BaseApiResponse changeMiscCharge(Long bookingId, String miscCharge, String userId) throws Exception { + BaseApiResponse processResult = new BaseApiResponse<>(); + + // 1. 基础数据获取与准备 + Bookings bookings = bookingDao.findById(bookingId).orElse(null); + + if (bookings == null) { + processResult.setMessage("Misc charge not found"); + processResult.setSuccess(false); + return processResult; + } + + boolean needSetPost = StringUtils.isEmpty(bookings.getMiscCharge()); + + boolean isMock = sysSettingService.isMockReplicate(); + String miscChargeValue = miscCharge == null ? "" : miscCharge.trim(); + + // 2. 根据 Property 的 Category 区分 OPERA / DAYLIGHT 流程 + CfgProperties property = propertyDao.getById(bookings.getPropertyId()); + + if ("DAYLIGHT".equalsIgnoreCase(property.getCategory())) { + // ==================== DAYLIGHT 流程 ==================== + String dateRange = DateTimeUtil.formatOperaCommentStayDateRange( + bookings.getCheckinDate(), bookings.getCheckoutDate(), bookings.getNumOfNight()); + + BaseApiResponse response = + dlService.daylightGetNoteListById(property.getDlPropertyId(), bookings.getDlReservationId()); + + if (response.isSuccess()) { + String comment = response.getData().getContent(); + comment = comment.replaceAll("(?i)", "\n"); + bookings.setOperaComment(comment); + } + + ReservationNoteResponse noteResponse = response.getData(); + + String newDaylightComment = buildNewDaylightComment( + bookings.getOperaComment(), bookings.getMiscCharge(), miscChargeValue, + dateRange, bookings.getSourceCode(), userId, bookings.getCreatedBy() + ); + + bookings.setMiscCharge(miscChargeValue); + bookings.setOperaComment(newDaylightComment); + + if (StringUtils.isNotBlank(userId)) { + bookings.setUpdatedBy(userId); + bookings.setUpdatedAt(new Date()); + } + + dlService.daylightUpdateReservationNote( + property.getDlPropertyId(), + bookings.getDlReservationId(), + noteResponse.getNoteId(), + newDaylightComment, + noteResponse.getVersion() + ); + + if (needSetPost) { + dlService.daylightSetPost(property.getDlPropertyId(), bookings.getDlAccountId()); + } + + Date checkInDate = bookings.getCheckinDate(); + Date checkOutDate = bookings.getCheckoutDate(); + String checkinDateStr = DateTimeUtil.getDateByFormat(checkInDate, "yyyy-MM-dd"); + String checkoutDateStr = DateTimeUtil.getDateByFormat(checkOutDate, "yyyy-MM-dd"); + DaylightReservationResponse daylightReservationByDlId = + dlService.getDaylightReservationByDlId(bookings.getDlReservationId(), property.getDlPropertyId()); + List daylightViewList = daylightViewDao.findBySectionPropertyBookingTypeRoomType( + bookings.getSectionId(), bookings.getPropertyId(), bookings.getBookingTypeId(), bookings.getRoomTypeId() + ); + + if (CollectionUtils.isNotEmpty(daylightViewList)) { + dlService.createDaylightCompRule( + daylightReservationByDlId.getAccountId(), + daylightReservationByDlId.getProfileId(), + property.getDlPropertyId(), + userId, + checkinDateStr, + checkoutDateStr, + daylightViewList, + miscChargeValue + ); + } + + Bookings changedBooking = bookingDao.save(bookings); + + processResult.setSuccess(true); + processResult.setData(changedBooking); + return processResult; + + } else if ("OPERA".equalsIgnoreCase(property.getCategory())) { + // ==================== OPERA 流程 ==================== + String dateRange = DateTimeUtil.formatOperaCommentStayDateRange( + bookings.getCheckinDate(), bookings.getCheckoutDate(), bookings.getNumOfNight()); + + // 2a. 获取最新的 OperaComment 状态 + Long bookingCommentId = bookings.getOperaCommentId(); + Integer resvNameId = bookings.getResvId() != null ? Integer.valueOf(bookings.getResvId()) : null; + LogUtil.info(BookingService.class, "Start GetOperaComment CommentId:" + bookingCommentId + " resvNameId:" + resvNameId); + + List commentList = operaDBBookingService.getBookingCommentByCommentId(bookingCommentId, resvNameId); + String commentType = null; + if (CollectionUtils.isNotEmpty(commentList)) { + OperaComment lastComment = commentList.getLast(); + bookings.setOperaComment(lastComment.getComments()); + bookings.setOperaCommentId(Long.valueOf(lastComment.getResvCommentId())); + commentType = lastComment.getCommentType(); + LogUtil.info(BookingService.class, "Get Comment Success: " + lastComment.getComments() + " CommentId: " + lastComment.getResvCommentId()); + } else { + LogUtil.info(BookingService.class, "Get Comment Failed, commentList is Empty"); + } + + // 2b. 构建新的 OperaComment 字符串 + String newOperaComment = buildNewOperaComment( + bookings.getOperaComment(), bookings.getMiscCharge(), miscChargeValue, + dateRange, bookings.getSourceCode(), userId, bookings.getCreatedBy() + ); + + // 2c. 更新 Booking 实体 + bookings.setMiscCharge(miscChargeValue); + bookings.setOperaComment(newOperaComment); + if (StringUtils.isNotBlank(userId)) { + bookings.setUpdatedBy(userId); + bookings.setUpdatedAt(new Date()); + } + + // 2d. 同步 OPERA 并落库 + if (!isMock) { + syncToOpera(bookings, miscChargeValue, newOperaComment, commentType); + } + Bookings changedBooking = bookingDao.save(bookings); + + processResult.setSuccess(true); + processResult.setData(changedBooking); + return processResult; + } + + processResult.setSuccess(false); + processResult.setMessage("Unknown category: " + property.getCategory()); + return processResult; + } + + private String buildNewDaylightComment(String originalComment, String oldMisCharge, String newMisCharge, + String dateRange, String sourceCode, String userId, String createdBy) { + return buildNewODCommentContent(originalComment, oldMisCharge, newMisCharge, + dateRange, sourceCode, userId, createdBy); + } + + private String buildNewOperaComment(String originalComment, String oldMisCharge, String newMisCharge, + String dateRange, String sourceCode, String userId, String createdBy) { + String comment = buildNewODCommentContent(originalComment, oldMisCharge, newMisCharge, + dateRange, sourceCode, userId, createdBy); + return comment.replace("\n", " ").replace("$", "$"); + } + + /** + * 构建 OD comment 的通用内容,统一使用真实换行符和美元符号。 + */ + private String buildNewODCommentContent(String originalComment, String oldMisCharge, String newMisCharge, + String dateRange, String sourceCode, String userId, String createdBy) { + String comment = originalComment == null ? "" : originalComment; + boolean hadOldMisCharge = oldMisCharge != null && !oldMisCharge.trim().isEmpty(); + + // 统一换行符 + if (!comment.isEmpty()) { + comment = comment.replace("\r\n", "\n").replace("\r", "\n") + .replace(" ", "\n").replace("$", "$"); + } + + if (!newMisCharge.isEmpty() && !comment.isEmpty()) { + boolean isBaseTemplate = comment.contains("(RM)COMP ..APP") + && comment.contains("\n\n" + dateRange + "," + sourceCode + "," + userId) + && !comment.contains("INC.CHRG$"); + + String amendLine = "AMEND INC.CHRG $" + newMisCharge + " AS " + userId + " ..APP"; + + if (!hadOldMisCharge && isBaseTemplate) { + // 情况 1:从基础模板首次添加 + comment = comment.replace("(RM)COMP ..APP", "(RM+INC$" + newMisCharge + ")COMP ..APP"); + String target = "\n\n" + dateRange + "," + sourceCode + "," + userId; + + if (comment.contains(target)) { + comment = comment.replace(target, "\n\n" + amendLine + "\n" + target.substring(2)); + } else { + int nnIdx = comment.indexOf("\n\n"); + comment = (nnIdx >= 0) + ? comment.substring(0, nnIdx + 2) + amendLine + "\n" + comment.substring(nnIdx + 2) + : comment + "\n" + amendLine; + } + } else { + // 情况 2:已有 INC.CHRG,或基础 comment 中已有 EXT 等附加行 + int rmIdxFull = comment.indexOf("(RM+INC$"); + if (rmIdxFull >= 0) { + int valStart = rmIdxFull + "(RM+INC$".length(); + int valEnd = comment.indexOf(")COMP", valStart); + if (valEnd > valStart) { + comment = comment.substring(0, valStart) + newMisCharge + comment.substring(valEnd); + } + } else { + int baseHeaderIndex = comment.indexOf("(RM)COMP ..APP"); + if (baseHeaderIndex >= 0) { + String miscChargeHeader = "(RM+INC$" + newMisCharge + ")COMP ..APP"; + comment = comment.substring(0, baseHeaderIndex) + + miscChargeHeader + + comment.substring(baseHeaderIndex + "(RM)COMP ..APP".length()); + } + } + + int headerEnd = comment.indexOf("..APP"); + + if (headerEnd >= 0) { + int insertPos = headerEnd + "..APP".length(); + + comment = comment.substring(0, insertPos) + + "\n\n" + + amendLine + + "\n" + + comment.substring(insertPos).trim(); + } else { + comment = comment + "\n" + amendLine; + } + } + } else { + // 全新构造 + comment = "(RM+INC$" + newMisCharge + ")COMP ..APP\n\n" + + "INC.CHRG$" + newMisCharge + "COMP BY " + createdBy + " ..APP\n" + + dateRange + "," + sourceCode + "," + userId; + } + + return comment; + } + + /** + * 构建 OD 延住(EXT)注释;Daylight 保留原始字符,Opera 在各自入口执行实体编码。 + * 注释格式:EXT <延住日期段>,OD,..APP + * 示例:EXT 23-26AUG,OD,WAI LEI..APP + * 延住日期段 = 原离店日 ~ 新离店日-1,例如:原离店 2026-08-09,延长至 2026-08-11 离店 → 09-10AUG + * 原 comment 有标准 RM header 时,header 后保留一个空行,再插入 EXT 行。 + */ + private String buildDaylightExtendComment(Bookings booking, Date originCheckoutDate, String booker) { + return buildODExtendCommentContent(booking, originCheckoutDate, booker); + } + + private String buildOperaExtendComment(Bookings booking, Date originCheckoutDate, String booker) { + String comment = buildODExtendCommentContent(booking, originCheckoutDate, booker); + if (comment == null) { + return null; + } + return comment.replace("\n", " ").replace("$", "$"); + } + + private String buildODExtendCommentContent(Bookings booking, Date originCheckoutDate, String booker) { + if (booking == null || originCheckoutDate == null) { + return null; + } + + String stayDate = formatExtStayDateRange(originCheckoutDate, booking.getCheckoutDate()); + String bookerName = StringUtils.defaultIfBlank(booker, booking.getBooker()); + String extLine = "EXT " + stayDate + ",OD," + bookerName + "..APP"; + + String existingComment = booking.getOperaComment(); + + String newComment; + + if (StringUtils.isBlank(existingComment)) { + newComment = extLine; + } else { + String comment = existingComment + .replace("\r\n", "\n") + .replace("\r", "\n") + .replace(" ", "\n") + .replace("$", "$"); + + int rmEndIndex = comment.indexOf("COMP ..APP"); + + if (rmEndIndex >= 0) { + rmEndIndex += "COMP ..APP".length(); + + newComment = comment.substring(0, rmEndIndex) + + "\n\n" + + extLine + + "\n" + + comment.substring(rmEndIndex).trim(); + } else { + newComment = extLine + "\n\n" + comment.trim(); + } + } + + LogUtil.info(BookingService.class, + "[buildODExtendCommentContent] bookingId=" + booking.getId() + + ", originCheckout=" + DateTimeUtil.getDateByFormat(originCheckoutDate, "yyyy-MM-dd") + + ", newCheckout=" + DateTimeUtil.getDateByFormat(booking.getCheckoutDate(), "yyyy-MM-dd") + + ", comment=" + extLine); + + return newComment; + } + + /** + * 延住日期段格式化:dd-ddMMM(月份大写、无空格) + * 单晚:09AUG;同月多晚:09-10AUG;跨月:30AUG-01SEP + */ + private String formatExtStayDateRange(Date originCheckout, Date newCheckout) { + if (originCheckout == null) { + return ""; + } + Locale en = Locale.ENGLISH; + Date lastNight = newCheckout != null ? DateTimeUtil.addDay(newCheckout, -1) : null; + if (lastNight == null || lastNight.before(originCheckout)) { + // 无有效延住,仅显示原离店日 + return DateTimeUtil.getDateByFormat(originCheckout, "ddMMM", en).toUpperCase(en); + } + String firstDay = DateTimeUtil.getDateByFormat(originCheckout, "dd", en); + String firstMonth = DateTimeUtil.getDateByFormat(originCheckout, "MMM", en).toUpperCase(en); + String lastDay = DateTimeUtil.getDateByFormat(lastNight, "dd", en); + String lastMonth = DateTimeUtil.getDateByFormat(lastNight, "MMM", en).toUpperCase(en); + if (firstDay.equals(lastDay) && firstMonth.equals(lastMonth)) { + // 单晚:09AUG + return firstDay + firstMonth; + } + if (firstMonth.equals(lastMonth)) { + // 同月多晚:09-10AUG + return firstDay + "-" + lastDay + firstMonth; + } + // 跨月:30AUG-01SEP + return firstDay + firstMonth + "-" + lastDay + lastMonth; + } + + private String extractMisCharge(String comment) { + if (comment == null || comment.isEmpty()) { + return ""; + } + + // 还原转义 + String normalizedComment = comment + .replace(" ", "\n") + .replace("$", "$"); + + Pattern pattern = Pattern.compile("AMEND INC\\.CHRG\\s+\\$(\\S+)\\s+AS"); + + Matcher matcher = pattern.matcher(normalizedComment); + + if (matcher.find()) { + return matcher.group(1); + } + + return ""; + } + + /** + * 辅助方法 2:专门处理同步至 OPERA 的外部网络请求(明确区分 MisCharge 修改和 Comment 修改) + */ + private void syncToOpera(Bookings bookings, String misChargeValue, String newOperaComment, String commentType) throws Exception { + if (bookings.getConfirmationNo() == null) return; + + // 1. 同步修改 MisCharge + ModifyBookingRequest misChargeRequest = new ModifyBookingRequest(); + misChargeRequest.setMiscCharge(misChargeValue); + misChargeRequest.setBooking(bookings); + operaService.modifyMiscCharge(misChargeRequest); + LogUtil.info(BookingService.class, "OPERA misCharge modified. New Comment: " + newOperaComment); + + // 2. 同步修改 OperaComment + CfgProperties property = propertyDao.getById(bookings.getPropertyId()); + GuestRequestsRequest cashCommentRequest = new GuestRequestsRequest(); + cashCommentRequest.setProperty(property); + cashCommentRequest.setComment(newOperaComment); + cashCommentRequest.setConfirmationNo(bookings.getConfirmationNo()); + + if (bookings.getOperaCommentId() != null) { + cashCommentRequest.setActionType("UPDATE"); + cashCommentRequest.setCommentId(bookings.getOperaCommentId()); + if (commentType != null) { + cashCommentRequest.setCommentType(commentType); + } + } else { + cashCommentRequest.setActionType("ADD"); + cashCommentRequest.setCommentType("CASHIER"); + } + + LogUtil.info(BookingService.class, "Start opera change comment, Action Type: " + cashCommentRequest.getActionType()); + JSONObject cashCommentResponse = operaService.guestRequests(cashCommentRequest); + LogUtil.info(BookingService.class, "End opera change comment"); + + if (cashCommentResponse != null && cashCommentResponse.get("commentId") != null) { + Long newCommentId = cashCommentResponse.getLong("commentId"); + if (!Objects.isNull(newCommentId)) { + bookings.setOperaCommentId(newCommentId); + } + } + } + + public void insertCommentAndMiscChargeFromDaylight(BookingDto dto) { + + String dlReservationId = dto.getDlReservationId(); + String dlPropertyId = dto.getDlPropertyId(); + +// if (StringUtils.isNotEmpty(dto.getOperaComment())) return; + + if (StringUtils.isEmpty(dlReservationId) || StringUtils.isEmpty(dlPropertyId)) return; + + BaseApiResponse response + = dlService.daylightGetNoteListById(dlPropertyId, dlReservationId); + + if (response.isSuccess()) { + ReservationNoteResponse data = response.getData(); + + if (data != null) { + String comment = data.getContent(); + if (comment != null) { + Matcher miscChargeMatcher = Pattern + .compile("(?:\\$|$)\\s*([0-9]+(?:\\.[0-9]+)?)", Pattern.CASE_INSENSITIVE) + .matcher(comment); + if (miscChargeMatcher.find()) { + dto.setMiscCharge(miscChargeMatcher.group(1)); + } + comment = comment.replaceAll("(?i)", "\n"); + } + dto.setOperaComment(comment); + } + } + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/services/NonMGMBookingService.java b/src/main/java/com/mgm/mcrm/booking/services/NonMGMBookingService.java new file mode 100644 index 0000000..e2e9f88 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/services/NonMGMBookingService.java @@ -0,0 +1,955 @@ +package com.mgm.mcrm.booking.services; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.mgm.mcrm.allotment.models.CfgOtherAllotment; +import com.mgm.mcrm.allotment.models.CfgOtherAppChannel; +import com.mgm.mcrm.approval.dtos.GetApproverRequest; +import com.mgm.mcrm.approval.service.ApprovalService; +import com.mgm.mcrm.appsetting.models.CfgSettings; +import com.mgm.mcrm.basesetting.daylight.models.*; +import com.mgm.mcrm.basesetting.property.models.CfgProperties; +import com.mgm.mcrm.basesetting.room.models.CfgOtherRoomStatus; +import com.mgm.mcrm.basesetting.room.models.CfgRooms; +import com.mgm.mcrm.basesetting.team.models.CfgOtherUserMapping; +import com.mgm.mcrm.booking.dtos.BookingDateEntry; +import com.mgm.mcrm.booking.dtos.BookingDto; +import com.mgm.mcrm.booking.mappers.BookingMapper; +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.booking.models.BookingsView; +import com.mgm.mcrm.booking.models.CfgBookingTypes; +import com.mgm.mcrm.booking.models.NonMGMBookings; +import com.mgm.mcrm.booking.repositories.*; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.common.dtos.mgm_api.*; +import com.mgm.mcrm.common.enums.EnumBookingStatus; +import com.mgm.mcrm.common.services.MGMApiService; +import com.mgm.mcrm.common.utils.LogUtil; +import com.mgm.mcrm.logging.models.SysLogOperation; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; + +import jakarta.transaction.Transactional; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.auth0.jwt.JWT; +import com.auth0.jwt.interfaces.DecodedJWT; + +import com.mgm.mcrm.common.utils.DateTimeUtil; +import com.mgm.mcrm.common.utils.ExcelUtils; +import com.mgm.mcrm.common.utils.NetworkUtil; +import com.mgm.mcrm.common.constants.SysConstants; +import com.mgm.mcrm.basesetting.daylight.repositories.MarketCodeDao; +import com.mgm.mcrm.allotment.repositories.OtherAllotmentDao; +import com.mgm.mcrm.basesetting.room.repositories.OtherRoomStatusDao; +import com.mgm.mcrm.basesetting.daylight.repositories.OtherSegmentDao; +import com.mgm.mcrm.basesetting.team.repositories.OtherUserMappingDao; +import com.mgm.mcrm.basesetting.property.repositories.PropertyDao; +import com.mgm.mcrm.basesetting.room.repositories.RoomDao; +import com.mgm.mcrm.basesetting.daylight.repositories.SourceCodeDao; +import com.mgm.mcrm.common.dtos.data_import.ValidateResult; +import com.mgm.mcrm.common.dtos.data_import.booking.OtherBookingImportRow; +import com.mgm.mcrm.common.dtos.excel_model.ImportDefine; +import com.mgm.mcrm.player.services.PlayerService; +import com.mgm.mcrm.appsetting.services.SettingService; +import com.mgm.mcrm.authorization.services.MgmUserService; +import com.mgm.mcrm.logging.services.SysLogBookingService; +import com.mgm.mcrm.logging.services.SysLogOperationService; + + +@Service +public class NonMGMBookingService { + @Resource + private MGMApiService mgmApiService; + @Resource + private NonMGMBookingDao nonMgmBookingDao; + @Resource + private NonMGMStatusMappingDao nonMgmStatusDao; + @Resource + private PropertyDao propertyDao; + @Resource + private RoomDao roomDao; + @Lazy + @Autowired + private BookingService bookingService; + @Resource + private BookingDao bookingDao; + @Autowired + private OtherAppChannelDao otherChannelDao; + @Autowired + private OtherAllotmentDao otherAllotmentDao; + @Autowired + private OtherUserMappingDao otherUserMappingDao; + @Resource + private MarketCodeDao marketDao; + @Resource + private OtherRoomStatusDao roomStatusDao; + @Resource + private BookingViewDao bookingViewDao; + @Resource + private SettingService settingService; + @Resource + private SysLogBookingService sysLogBookingService; + @Resource + private OtherRoomStatusDao otherRoomStatusDao; + @Resource + private OtherFollowUpStatusDao otherFollowUpStatusDao; + @Resource + private MarketCodeDao marketCodeDao; + @Resource + private BookingTypeDao bookingTypeDao; + @Resource + private OtherSegmentDao segmentDao; + @Resource + private SysLogOperationService sysLogOperationService; + @Resource + private PlayerService playerService; + @Resource + private SourceCodeDao sourceCodeDao; + @Resource + private MgmUserService mgmUserService; + @Resource + private ApprovalService approvalService; + + @Autowired + private BookingMapper bookingMapper; + + public BaseApiResponse> createOtherBooking(BookingDto param, HttpServletRequest request, UserInfoApiRecord userInfo, CfgProperties property) throws Exception { + BaseApiResponse> processResult= new BaseApiResponse<>(); + Date createDate = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + + String playerId = param.getPlayerId(); + Long bookingTypeId = param.getBookingTypeId(); + Long propertyId = param.getPropertyId(); + Long roomId = param.getRoomId(); + String roomName = param.getRoom(); + String specialCode = param.getSpecialCode(); + JSONArray sharer = param.getSharerList(); + List dateList = param.getDateList(); + String remark = param.getRemark(); + String userId = userInfo.getUserId(); + String userName = userInfo.getUserName(); + String createdByName = userInfo.getUserName(); + String groupId = param.getGroupId(); + Long sectionId = param.getSectionId(); + PlayerProfileEntry member = param.getMember(); + Long bedTypeMasterGroupId = param.getBedTypeId(); + String bedTypeName = param.getBedTypeName(); + String etaTime = param.getEtaTime(); + String marketCode = ""; + Long segmentId; + // 筛选出符合条件的 mapping记录 + List userMappingList = + otherUserMappingDao.findBySectionIdAndPropertyIdAndBookingTypeId(sectionId,propertyId, bookingTypeId); + + if(userMappingList!=null && !userMappingList.isEmpty()) { + segmentId = userMappingList.getFirst().getSegmentId(); + Long marketCodeId = userMappingList.getFirst().getMarketCodeId(); + if(marketCodeId!=null) { + CfgMarketCodes market = marketDao.findById(marketCodeId).orElse(null); + if(market!=null) { + marketCode = market.getCode(); + } + } + }else{ + JSONObject exption = new JSONObject(); + exption.put("errorCode", "USERMAPPING_NOT_FOUND"); + exption.put("errorMessage", "[BookingService][createOtherBooking]user mapping not found."); + throw new Exception(JSONObject.toJSONString(exption)); + } + + if(segmentId==null) { + JSONObject exption = new JSONObject(); + exption.put("errorCode", "SEGMENT_NOT_FOUND"); + exption.put("errorMessage", "[BookingService][createOtherBooking]segment not found."); + throw new Exception(JSONObject.toJSONString(exption)); + } + + List resultBookings = new ArrayList<>(); + for(int i=0;i dateArr = dateItem.getDate(); + Date checkinDate = DateTimeUtil.getDateFromString(String.valueOf(dateArr.getFirst()), "yyyy-MM-dd"); + Date checkoutDate = DateTimeUtil.getDateFromString(String.valueOf(dateArr.getLast()), "yyyy-MM-dd"); + String numOfNight = String.valueOf(dateItem.getNumOfNight()); + String bookRemark = String.valueOf(dateItem.getRemark()); + if(!StringUtils.isEmpty(bookRemark)) booking.setRemark(bookRemark); + + String bookingStatus = dateItem.getBookingStatus(); + + //获取room type + booking = bookingService.getRoomType(booking,roomId,checkinDate,checkinDate,bedTypeMasterGroupId); + + //获取other room status + CfgOtherRoomStatus roomStatus = roomStatusDao.findByStatusName("Pending"); + if(roomStatus!=null) { + booking.setOtherRoomStatusId(roomStatus.getId()); + } + + //TODO Add ApprovalRouting Logic + String checkinDateStr = DateTimeUtil.getDateByFormat(checkinDate, "yyyy-MM-dd"); + String checkoutDateStr = DateTimeUtil.getDateByFormat(checkoutDate, "yyyy-MM-dd"); + CfgRooms room = roomDao.findById(param.getRoomId()); + boolean isWaitlist = dateItem.getStatus() != null && dateItem.getStatus() == 1; + boolean isApproval = param.getIsApproval() != null && param.getIsApproval() == 1; + + CfgBookingTypes cfgBookingType = bookingTypeDao.findCfgBookingTypesById(param.getBookingTypeId()); + GetApproverRequest approverRequest = new GetApproverRequest(); + approverRequest.setBookingType(cfgBookingType.getName()); + approverRequest.setPlayerId(playerId); + approverRequest.setRoomCategory(room.getCategory()); + approverRequest.setPropertyName(property.getName()); + approverRequest.setCheckInDate(checkinDateStr); + approverRequest.setCheckOutDate(checkoutDateStr); + String routingReason = param.getRoutingReason(); + String approvalStatus; + if (isApproval) { + approvalStatus = "AP"; + } else if (isWaitlist) { + approvalStatus = "W"; + } else { + approvalStatus = "PN"; + } + if (isApproval) { + BaseApiResponse approver = approvalService.getApprover(request, approverRequest); + List returnData = approver.getData().getRecords(); + LogUtil.info(BookingService.class, "RoutingReason Befor:" + routingReason); + if (StringUtils.isEmpty(routingReason)) { + routingReason = approver.getData().getStatusDescription(); + } + LogUtil.info(BookingService.class, "RoutingReason After:" + routingReason); + } + + booking.setCheckinDate(checkinDate); + booking.setCheckoutDate(checkoutDate); + booking.setNumOfNight(Integer.valueOf(numOfNight)); + booking.setApproveStatus(approvalStatus); + List dateArray = new ArrayList<>(); + dateArray.add(dateItem); + booking.setDateList(JSONArray.toJSONString(dateArray)); + Bookings saveBooking = new Bookings(); + + if(submitTag && !bookingStatus.equals("PN")) { // 这里的bookingStatus当时是用来防止后退的,迟点没用把它删了 + if(!isWaitlist && !isApproval) { + booking.setRemark(null); // 把不是waitlist中的remark清除 + saveBooking = bookingDao.save(booking); + //扣减房间 + processOtherAllotment(roomId, checkoutDate, checkinDate, propertyId, segmentId); + }else { + saveBooking = bookingDao.save(booking); + } + resultBookings.add(booking); + sysLogBookingService.saveLogBooking(resultBookings, request, "", "", "Create Booking(Sync from Mobile APP)",""); + } + + if (saveBooking.getId()!=null && isApproval){ + approvalService.createApprovalRouting(booking, param.getRouterToApproverId(), param.getRouterToApproverName(), param.getRequestReasonId(), routingReason); + } + } + + processResult.setSuccess(true); + processResult.setData(resultBookings); + + return processResult; + } + + public List getDBBookingsByPlayer(String playerId) throws Exception { + //未过cutoff time,查询checkout date大于等于今天。过了查询大于今天的。 + List bookingList = new ArrayList(); + String date = DateTimeUtil.getDateByFormat(new Date(), "yyyy-MM-dd"); + CfgSettings cutoffTime = settingService.getSettingByKey("OTHER_BOOKING_CUTOFF_TIME"); + String cutoffTimeValue = cutoffTime.getKeyValues(); + Date curentTime = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm"); + Date getTime = DateTimeUtil.getDateFromString(date+" "+cutoffTimeValue, "yyyy-MM-dd HH:mm"); + Date queryDate = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd"); + if(curentTime.getTime()>getTime.getTime()) { + queryDate = DateTimeUtil.addDay(queryDate, 1); + } + + Date endDay = new Date(); + CfgSettings operaMaxSearch = settingService.getSettingByKey(SysConstants.MAX_OPERA_BOOKING_DAYS); + endDay = DateTimeUtil.addDay(DateTimeUtil.getDateFromString(date, "yyyy-MM-dd"), + Integer.valueOf(operaMaxSearch.getKeyValues())); + Date endDate = DateTimeUtil.getDateFromString(DateTimeUtil.getDateByFormat(endDay, "yyyy-MM-dd"), "yyyy-MM-dd"); + bookingList = bookingViewDao.findNonMGMBooking(playerId,queryDate,endDate); + return bookingList; + } + + private BookingsView convertBookingFromRecord(NonMGMBookingRecord rec,String playerId) { + BookingsView booking = null; + if(rec!=null) { + booking = new BookingsView(); + NonMGMBookings nonMGMBooking = null; + Date currentTime = new Date(); + if(StringUtils.isNotBlank(rec.getConfirmationNumber())) { + List matchBookings = nonMgmBookingDao.findAllByPlayerIdAndConfirmationNo(playerId, rec.getConfirmationNumber()); + if(matchBookings!=null) { + if(!matchBookings.isEmpty()) { + nonMGMBooking = matchBookings.getFirst(); + } + if(matchBookings.size()>1) { + for(int i=1;i statusMappings = nonMgmStatusDao.findAllByStatusCodeAndPropertyId(rec.getRoomTypeStatusCode(),nonMGMBooking.getPropertyId()); + if(statusMappings!=null && !statusMappings.isEmpty()) { + statusMap = statusMappings.getFirst(); + nonMGMBooking.setRoomId(statusMap.getRoomId()); + nonMGMBooking.setStatusName(EnumBookingStatus.getStatusByDaylightStatus(statusMap.getStatusName())); + } + } + //-- + nonMGMBooking.setRecUpdatedAt(currentTime); + nonMgmBookingDao.save(nonMGMBooking); + //-- Convert to booking View + booking.setId(nonMGMBooking.getId()); + booking.setConfirmationNo(nonMGMBooking.getConfirmationNo()); + booking.setPropertyName(nonMGMBooking.getProperty()); + booking.setPropertyId(nonMGMBooking.getPropertyId()); + booking.setPlayerId(playerId); + booking.setCheckinDate(nonMGMBooking.getCheckInDate()); + booking.setCheckoutDate(nonMGMBooking.getCheckOutDate()); + booking.setRoomId(nonMGMBooking.getRoomId()); + if(nonMGMBooking.getRoomId()!=null) { + CfgRooms roomObj = roomDao.findById(nonMGMBooking.getRoomId()); + if(roomObj!=null) { + booking.setRoomCategory(roomObj.getRoomCategory()); + } + } + booking.setLastOperaStatus(nonMGMBooking.getStatusName()); + booking.setCreatedAt(nonMGMBooking.getCreatedOn()); + booking.setCreatedByName(nonMGMBooking.getCreatedBy()); + booking.setPropertyCategory("OTHER"); + booking.setApproveStatus("N"); + booking.setBookingTypeName("Mass"); + } + return booking; + } + + //扣减other booking allotment + public void processOtherAllotment(Long roomId,Date checkoutDate,Date checkinDate,Long propertyId,Long segmentId) { + List roomIds = new ArrayList(); + roomIds.add(Long.valueOf(String.valueOf(roomId))); + Date endDate = DateTimeUtil.addDay(checkoutDate, -1); + List criterias = otherAllotmentDao.findByRoomIdInAndPropertyIdAndBookDateBetween + (roomIds,propertyId,checkinDate,endDate); + List updateChannelList = new ArrayList(); + Long[] roomStatusId = otherRoomStatusDao.findIsPickUpId(); + for(CfgOtherAllotment c:criterias) { + CfgOtherAppChannel channel = new CfgOtherAppChannel(); + Set channels = c.getChannels(); + for(CfgOtherAppChannel a:channels) { + if(a.getSegmentId()!=null&&segmentId!=null) { + if(a.getSegmentId().longValue()==segmentId.longValue()) { + channel = a; + int pickUp = 0; + Integer appChannel = 0; + pickUp = bookingDao.getOtherPickupBooking(propertyId, roomId, segmentId, c.getBookDate(), roomStatusId); + if(channel.getAppChannel()!=null) { + appChannel = channel.getAppChannel(); + } + channel.setPickedUp(pickUp); + channel.setAvailable(appChannel-channel.getPickedUp()); + updateChannelList.add(channel); + } + } + } + } + if(!updateChannelList.isEmpty()) otherChannelDao.saveAll(updateChannelList); + } + + public BaseApiResponse parseImportExcel(String importFilePath) { + BaseApiResponse result=new BaseApiResponse<>(); + String importName = "IMPORT_OTHER_BOOKING"; + ImportDefine importDef = ExcelUtils.getImportDefineByName(importName); + if(importDef!=null) { + BaseApiResponse> importResult = ExcelUtils.importDataBlock(importDef,importFilePath,null); + if(!importResult.isSuccess()) { + result.setSuccess(false); + result.setMessage(importResult.getMessage()); + }else { + if(importResult.getData()!=null) { + List dataList = importResult.getData(); + if(!dataList.isEmpty()) { + List importList = (List)dataList.getFirst(); + ValidateResult validateRes = validateImportData(importList); + if(validateRes.getResultCount()>0) { + result.setSuccess(true); + result.setData(validateRes); + }else { + result.setSuccess(false); + result.setMessage("No import data detected"); + } + }else { + result.setSuccess(false); + result.setMessage("No import data detected"); + } + }else { + result.setSuccess(false); + result.setMessage("Empty import data"); + } + } + }else { + result.setSuccess(false); + result.setMessage("Import ["+importName+"] not defined"); + } + return result; + } + + private long getMatchPropertyId(List properties, String name) { + long matchId=0; + for(CfgProperties item:properties) { + if(Strings.CI.equals(item.getName(), name)) { + matchId = item.getId().intValue(); + break; + } + } + return matchId; + } + + private long getMatchRoomId(List rooms, String name, Long propertyId) { + long matchId=0; + for(CfgRooms item:rooms) { + if(propertyId!=null&&item.getPropertyId()!=null) { + if(Strings.CI.equals(item.getName(), name)&& + Long.valueOf(item.getPropertyId()).equals(propertyId)) { + matchId = item.getId().intValue(); + break; + } + } + } + return matchId; + } + + private long getMatchBookingTypeId(List bookingTypes, String name) { + long matchId=0; + for(CfgBookingTypes item:bookingTypes) { + if(Strings.CI.equals(item.getName(), name)) { + matchId = item.getId().intValue(); + break; + } + } + return matchId; + } + + private long getMatchMarketCodeId(List marketCodes, String name) { + long matchId=0; + for(CfgMarketCodes item:marketCodes) { + if(Strings.CI.equals(item.getCode(), name)) { + matchId = item.getId().intValue(); + break; + } + } + return matchId; + } + + private long getMatchSegmentId(List segment, String name) { + long matchId=0; + for(CfgOtherSegment item:segment) { + if(Strings.CI.equals(item.getSegmentName(), name)) { + matchId = item.getId().intValue(); + break; + } + } + return matchId; + } + + private long getMatchFollowUpStatusId(List followUpStatus, String name) { + long matchId=0; + for(CfgOtherFollowUpStatus item:followUpStatus) { + if(Strings.CI.equals(item.getName(), name)) { + matchId = item.getId().intValue(); + break; + } + } + return matchId; + } + + private long getMatchRoomStatusId(List roomStatus, String name) { + long matchId=0; + for(CfgOtherRoomStatus item:roomStatus) { + if(Strings.CI.equals(item.getStatusName(), name)) { + matchId = item.getId().intValue(); + break; + } + } + return matchId; + } + + private long getMatcSourceCode(List source, String name) { + long matchId=0; + for(CfgSourceCodes item:source) { + if(Strings.CI.equals(item.getCode(), name)) { + matchId = item.getId().intValue(); + break; + } + } + return matchId; + } + + private ValidateResult validateImportData(List importList) { + ValidateResult result=new ValidateResult(); + int totalRows=0; + int failedRows=0; + int successRows=0; + Map uniqueKeys = new HashMap(); + if(!importList.isEmpty()) { + totalRows = importList.size(); + List followUpStatusList = otherFollowUpStatusDao.findAll(); + List roomStatusList = otherRoomStatusDao.findAll(); + List propertyList = propertyDao.findAll(); + List roomList = roomDao.findAll(); + List marketCodeList = marketCodeDao.findAll(); + List bookingTypeList = bookingTypeDao.findAll(); + List segmentList = segmentDao.findAll(); + List sourceCodeList = sourceCodeDao.findAll(); + + for(int i=0;i0) { + pItem.setOtherFollowUpStatusId(followUpStatusId); + }else { + errMsg+= "No match Follow Up Status of ["+pItem.getOtherFollowUpStatusName()+"];"; + isPassed=false; + } + } + if(StringUtils.isBlank(pItem.getOtherRoomStatusName())){ + errMsg+= "Room Status is blank;"; + isPassed=false; + }else { + long roomStatusId = this.getMatchRoomStatusId(roomStatusList, pItem.getOtherRoomStatusName()); + if(roomStatusId>0) { + pItem.setOtherRoomStatusId(roomStatusId); + }else { + errMsg+= "No match Room Status of ["+pItem.getOtherFollowUpStatusName()+"];"; + isPassed=false; + } + } + if(StringUtils.isBlank(pItem.getPropertyName())){ + errMsg+= "Property Name is blank;"; + isPassed=false; + }else { + long propertyId = this.getMatchPropertyId(propertyList, pItem.getPropertyName()); + if(propertyId>0) { + pItem.setPropertyId(propertyId); + }else { + errMsg+= "No match Property of ["+pItem.getPropertyName()+"];"; + isPassed=false; + } + } + if(StringUtils.isBlank(pItem.getRoomName())){ + errMsg+= "Room Type is blank;"; + isPassed=false; + }else { + if(pItem.getPropertyId()!=null) { + long roomId = this.getMatchRoomId(roomList, pItem.getRoomName(),pItem.getPropertyId()); + if(roomId>0) { + pItem.setRoomId(roomId); + }else { + errMsg+= "No match Room Type of ["+pItem.getRoomName()+"];"; + isPassed=false; + } + } + } + if(StringUtils.isBlank(pItem.getMarketCodeName())){ + errMsg+= "Market Code is blank;"; + isPassed=false; + }else { + long rateCodeId = this.getMatchMarketCodeId(marketCodeList, pItem.getMarketCodeName()); + if(rateCodeId>0) { + pItem.setMarketCodeId(rateCodeId); + }else { + errMsg+= "No match Market Code of ["+pItem.getMarketCodeName()+"];"; + isPassed=false; + } + } + if(StringUtils.isBlank(pItem.getSegmentName())){ + errMsg+= "Segment is blank;"; + isPassed=false; + }else { + long segmentId = this.getMatchSegmentId(segmentList, pItem.getSegmentName()); + if(segmentId>0) { + pItem.setSegmentId(segmentId); + }else { + errMsg+= "No match Segment of ["+pItem.getSegmentName()+"];"; + isPassed=false; + } + } + if(StringUtils.isBlank(pItem.getBookingTypeName())){ + if(!Strings.CI.equals(pItem.getSegmentName(),"admin")&&!Strings.CI.equals(pItem.getSegmentName(),"nfro")) { + errMsg+= "Booking Type is blank;"; + isPassed=false; + } + + }else { + long bookingTypeId = this.getMatchBookingTypeId(bookingTypeList, pItem.getBookingTypeName()); + if(bookingTypeId>0) { + pItem.setBookingTypeId(bookingTypeId); + }else { + errMsg+= "No match Booking Type of ["+pItem.getBookingTypeName()+"];"; + isPassed=false; + } + } + + if(StringUtils.isBlank(pItem.getPlayerId())){ + if(!Strings.CI.equals(pItem.getSegmentName(),"admin")&&!Strings.CI.equals(pItem.getSegmentName(),"nfro")) { + errMsg+= "Player Id is blank;"; + isPassed=false; + } + }else { + if(StringUtils.length(pItem.getPlayerId())!=8) { + errMsg+= "Player Id invalid;"; + isPassed=false; + }else { + BaseApiResponse serviceResult = playerService.findWebPlayerProfileByPlayerId(pItem.getPlayerId()); + if(serviceResult.isSuccess()) { + pItem.setPlayerId(pItem.getPlayerId()); + }else { + errMsg+= serviceResult.getMessage()+";"; + isPassed=false; + } + } + } + if(StringUtils.isBlank(pItem.getApproverId())){ +// errMsg+= "Approver Id is blank;"; +// isPassed=false; + }else { + if(StringUtils.length(pItem.getApproverId())!=6) { + errMsg+= "Approver Id invalid;"; + isPassed=false; + }else { + pItem.setApproverId(pItem.getApproverId()); + } + } + if(StringUtils.isBlank(pItem.getBookerId())){ + errMsg+= "Booker Id is blank;"; + isPassed=false; + }else { + if(StringUtils.length(pItem.getBookerId())!=6) { + errMsg+= "Booker Id invalid;"; + isPassed=false; + }else { + BaseApiResponse userInfoRes = mgmUserService.findUserInfoByUserId(pItem.getBookerId()); + if(userInfoRes.isSuccess()) { + pItem.setBookerId(pItem.getBookerId()); + }else { + errMsg+= userInfoRes.getMessage()+";"; + isPassed=false; + } + } + } + if(StringUtils.isBlank(pItem.getCheckinDate())){ + errMsg+= "Check In Date is blank;"; + isPassed=false; + }else { + try { + DateTimeUtil.getDateFromString(pItem.getCheckinDate(), "yyyy-MM-dd"); + if(!DateTimeUtil.isValidDate(pItem.getCheckinDate())) { + errMsg+= "Check In Date invalid;"; + isPassed=false; + } + } catch (Exception e) { + errMsg+= "Check In Date invalid;"; + isPassed=false; + } + + } + if(StringUtils.isBlank(pItem.getCheckoutDate())){ + errMsg+= "Check Out Date is blank;"; + isPassed=false; + }else { + try { + DateTimeUtil.getDateFromString(pItem.getCheckoutDate(), "yyyy-MM-dd"); + if(!DateTimeUtil.isValidDate(pItem.getCheckoutDate())) { + errMsg+= "Check Out Date invalid;"; + isPassed=false; + } + } catch (Exception e) { + errMsg+= "Check Out Date invalid;"; + isPassed=false; + } + } + if(StringUtils.isBlank(pItem.getSourceCodeName())){ + errMsg+= "Source Code is blank;"; + isPassed=false; + }else { + long sourceCodeId = this.getMatcSourceCode(sourceCodeList, pItem.getSourceCodeName()); + if(sourceCodeId>0) { + pItem.setSouceCodeId(sourceCodeId); + }else { + errMsg+= "No match Source Code of ["+pItem.getSourceCodeName()+"];"; + isPassed=false; + } + } + JSONArray sharerList = new JSONArray(); + if(!StringUtils.isBlank(pItem.getSharer())){ + String[] sList = StringUtils.split(pItem.getSharer(),";"); + for(String s:sList) { + JSONObject sl = new JSONObject(); + String[] gsList = StringUtils.split(s,":"); + if(gsList.length==2) { + sl.put("playerId", gsList[0]); + sl.put("name", gsList[1]); + }else { + sl.put("playerId", ""); + sl.put("name", s); + } + + sharerList.add(sl); + } + } + pItem.setSharerList(sharerList.toJSONString()); + pItem.setValidatePassed(isPassed); + pItem.setErrorMessage(errMsg); + if(isPassed) + successRows++; + else + failedRows++; + } + //-- + } + result.setResultCount(totalRows); + result.setPassedCount(successRows); + result.setFailedCount(failedRows); + result.setResultRows(importList); + return result; + } + + public BaseApiResponse importBatch(List importRows,HttpServletRequest request) throws Exception { + BaseApiResponse result=new BaseApiResponse<>(); + if(importRows!=null && !importRows.isEmpty()) { + ValidateResult validateRes = validateImportData(importRows); + if(validateRes.getResultCount()>0 && validateRes.getFailedCount() <=0) { + Date currentTime = new Date(); + List roomStatusList = otherRoomStatusDao.findAll(); + for(int i=0;i serviceResult = playerService.findWebPlayerProfileByPlayerId(pItem.getPlayerId()); + if(serviceResult.isSuccess()) { + member = serviceResult.getData(); + } + } + if(!StringUtils.isEmpty(pItem.getBookerId())) { + BaseApiResponse userInfoRes = mgmUserService.findUserInfoByUserId(pItem.getBookerId()); + if(userInfoRes.isSuccess()) { + userInfo = userInfoRes.getData(); + } + } + + newBook.setOtherFollowUpStatusId(pItem.getOtherFollowUpStatusId()); + newBook.setOtherRoomStatusId(pItem.getOtherRoomStatusId()); + newBook.setRoomId(pItem.getRoomId()); + newBook.setRoom(pItem.getRoomName()); + newBook.setPropertyId(pItem.getPropertyId()); + newBook.setBookingTypeId(pItem.getBookingTypeId()); + newBook.setMarketCode(pItem.getMarketCodeName()); + newBook.setSegmentId(pItem.getSegmentId()); + newBook.setCreatedBy(pItem.getBookerId()); + newBook.setSourceCode(pItem.getSourceCodeName()); + newBook.setCategory("OTHER"); + + if(userInfo.getUserName()!=null) { + newBook.setBooker(userInfo.getUserName()); + newBook.setCreatedByName(userInfo.getUserName()); + } + if(!StringUtils.isEmpty(pItem.getPlayerName())) { + if(pItem.getPlayerName().contains(",") && !pItem.getPlayerName().contains(", ")) { + pItem.setPlayerName(pItem.getPlayerName().replace(",", ", ")); + } + newBook.setMemberLastName(pItem.getPlayerName()); + }else if(member.getName()!=null) { + newBook.setMemberLastName(member.getName()); + } + if(member.getSalutation()!=null) { + newBook.setMemberTitle(member.getSalutation()); + } + newBook.setMember(JSONObject.toJSONString(member)); + if(!StringUtils.isEmpty(pItem.getApproverId())) { + newBook.setApprovedId(Long.valueOf(pItem.getApproverId())); + } + + newBook.setCheckinDate(DateTimeUtil.getDateFromString(pItem.getCheckinDate(), "yyyy-MM-dd")); + newBook.setCheckoutDate(DateTimeUtil.getDateFromString(pItem.getCheckoutDate(), "yyyy-MM-dd")); + newBook.setPlayerId(pItem.getPlayerId()); + newBook.setSharer(pItem.getSharerList()); + newBook.setConfirmationNo(pItem.getConfirmationNo()); + newBook.setRemark(pItem.getRemark()); + + newBook.setCreatedAt(currentTime); + newBook.setUpdatedAt(currentTime); + String approveStatus = "N"; + String lastOperaStatus=null; + CfgOtherRoomStatus roomStatus = null; + for(CfgOtherRoomStatus r:roomStatusList) { + if(r.getId()!=null&&pItem.getOtherRoomStatusId()!=null) { + if(r.getId().longValue()== pItem.getOtherRoomStatusId().longValue()) { + roomStatus = r; + } + } + + } + if(roomStatus!=null) { + if(roomStatus.getShowBooking()==0) { + approveStatus = "C"; + }else if(Strings.CS.equals("Pending", roomStatus.getStatusName())) { + approveStatus = "PN"; + }else { + approveStatus = "N"; + if(Strings.CS.equals("Reserved", roomStatus.getStatusName())) { + lastOperaStatus = "RESERVED"; + }else if(Strings.CS.equals("Checked In", roomStatus.getStatusName())) { + lastOperaStatus = "CHECKED_IN"; + } + } + } + newBook.setApproveStatus(approveStatus); + newBook.setLastOperaStatus(lastOperaStatus); + //获取room type + newBook = bookingService.getRoomType(newBook,newBook.getRoomId(),newBook.getCheckinDate(),newBook.getCheckoutDate(),null); + bookingDao.save(newBook); + //计算房间 + processOtherAllotment(newBook.getRoomId(), newBook.getCheckoutDate(), newBook.getCheckinDate(), newBook.getPropertyId(), newBook.getSegmentId()); + } + SysLogOperation sysLogOper = new SysLogOperation(); + String oldToken = request.getHeader("Authorization"); + if(oldToken==null) { + oldToken=""; + } + if(oldToken.startsWith("Bearer ")) { + oldToken = oldToken.substring(7); + } + DecodedJWT tokenData = JWT.decode(oldToken); + String loginId = tokenData.getClaim("login_id").asString(); + if (!StringUtils.isEmpty(loginId)) { + sysLogOper.setLoginId(loginId); + } + Date now = new Date(); + sysLogOper.setOccurTime(now); + sysLogOper.setSortOccurtime(now.getTime()); + sysLogOper.setIpAddress(NetworkUtil.getClientIpAddr(request)); + sysLogOper.setEventCode("booking_other_import"); + sysLogOper.setLogDesc(importRows.size()+" other property bookings uploaded"); + sysLogOper.setTagSuccess(1); + sysLogOperationService.save(sysLogOper); + + result.setSuccess(true); + }else { + result.setSuccess(false); + result.setMessage("Import data validate failed"); + result.setData(validateRes); + } + }else { + result.setSuccess(false); + result.setMessage("Empty import data"); + } + return result; + } + + @Transactional + public List getDBBookingsByPlayer_Optimize(String playerId) throws Exception { + //未过cutoff time,查询checkout date大于等于今天。过了查询大于今天的。 + List bookingList = new ArrayList(); + String date = DateTimeUtil.getDateByFormat(new Date(), "yyyy-MM-dd"); + CfgSettings cutoffTime = settingService.getSettingByKey("OTHER_BOOKING_CUTOFF_TIME"); + String cutoffTimeValue = cutoffTime.getKeyValues(); + Date curentTime = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm"); + Date getTime = DateTimeUtil.getDateFromString(date+" "+cutoffTimeValue, "yyyy-MM-dd HH:mm"); + Date queryDate = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd"); + if(curentTime.getTime()>getTime.getTime()) { + queryDate = DateTimeUtil.addDay(queryDate, 1); + } + + Date endDay = new Date(); + CfgSettings operaMaxSearch = settingService.getSettingByKey(SysConstants.MAX_OPERA_BOOKING_DAYS); + endDay = DateTimeUtil.addDay(DateTimeUtil.getDateFromString(date, "yyyy-MM-dd"), + Integer.valueOf(operaMaxSearch.getKeyValues())); + Date endDate = DateTimeUtil.getDateFromString(DateTimeUtil.getDateByFormat(endDay, "yyyy-MM-dd"), "yyyy-MM-dd"); + bookingList = bookingViewDao.findNonMGMBooking(playerId,queryDate,endDate); + return bookingMapper.viewToBookingDtoList(bookingList); + } + +} diff --git a/src/main/java/com/mgm/mcrm/booking/services/OWSTransactionsService.java b/src/main/java/com/mgm/mcrm/booking/services/OWSTransactionsService.java new file mode 100644 index 0000000..ccbcbd7 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/services/OWSTransactionsService.java @@ -0,0 +1,24 @@ +package com.mgm.mcrm.booking.services; + +import com.mgm.mcrm.booking.models.OWSTransactions; +import jakarta.annotation.Resource; + +import org.springframework.stereotype.Service; + +import com.mgm.mcrm.booking.repositories.OWSTransactionsRepository; + + + + +@Service +public class OWSTransactionsService { + @Resource + private OWSTransactionsRepository owsTransRepository; + + public OWSTransactions getOWSTransMaxId() { + return owsTransRepository.findMaxId(); + } + public OWSTransactions saveOWSTrans(OWSTransactions obj) { + return owsTransRepository.save(obj); + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/services/OperaDBBookingService.java b/src/main/java/com/mgm/mcrm/booking/services/OperaDBBookingService.java new file mode 100644 index 0000000..a894a09 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/services/OperaDBBookingService.java @@ -0,0 +1,221 @@ +package com.mgm.mcrm.booking.services; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import com.mgm.mcrm.booking.dtos.BookingDto; +import com.mgm.mcrm.booking.models.BookingsView; +import com.mgm.mcrm.booking.models.OperaComment; +import com.mgm.mcrm.booking.models.OperaDBBooking; +import com.mgm.mcrm.booking.models.OperaDBRate; +import com.mgm.mcrm.common.enums.EnumBookingStatus; +import com.mgm.mcrm.common.utils.LogUtil; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.StoredProcedureQuery; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +import com.mgm.mcrm.common.utils.DateTimeUtil; + + +@Service +public class OperaDBBookingService { + + @Autowired + @Qualifier("entityManagerOpera") + private EntityManager entityManager; + + @Autowired + @Qualifier("entityManagerFactoryOpera") + private EntityManagerFactory factory; + + public List getBookingsByConfirmationNo(String confirmationNo){ + EntityManager entity = this.factory.createEntityManager(); + List lists = new ArrayList(); + try { + StoredProcedureQuery store = entity.createNamedStoredProcedureQuery("getBookingsByConfirmationNo"); + store.setParameter("confirmation_no", confirmationNo); + lists = store.getResultList(); + entity.close(); + } catch (Exception e) { + entity.close(); + e.printStackTrace(); + } + List list = convertBookingList(lists); + + return list; + } + public List getBookingsByNameID(String nameId,String blockCode,Date endDate){ + EntityManager entity = this.factory.createEntityManager(); + List lists = new ArrayList(); + try { + StoredProcedureQuery store = entity.createNamedStoredProcedureQuery("getBookingsByNameID"); + store.setParameter("name_id", nameId); + store.setParameter("block_code", blockCode); + store.setParameter("enddate", endDate); + lists = store.getResultList(); + entity.close(); + } catch (Exception e) { + entity.close(); + e.printStackTrace(); + } + List list = convertBookingList(lists); + entity.close(); + return list; + } + + public List getBookingsByNameID_Optimize(String nameId, String blockCode, Date endDate){ + EntityManager entity = this.factory.createEntityManager(); + List operaDbBookings = new ArrayList(); + try { + StoredProcedureQuery store = entity.createNamedStoredProcedureQuery("getBookingsByNameID"); + store.setParameter("name_id", nameId); + store.setParameter("block_code", blockCode); + store.setParameter("enddate", endDate); + operaDbBookings = store.getResultList(); + entity.close(); + } catch (Exception e) { + entity.close(); + e.printStackTrace(); + } + List bookings = convertBookingList_Optimize(operaDbBookings); + entity.close(); + return bookings; + } + + public List getOperaNameIDByPlayerID(String playerId){ + EntityManager entity = this.factory.createEntityManager(); + List lists = new ArrayList(); + try { + StoredProcedureQuery store = entity.createNamedStoredProcedureQuery("getOperaNameIDByPlayerID"); + store.setParameter("player_id", playerId); + lists = store.getResultList(); + entity.close(); + } catch (Exception e) { + entity.close(); + e.printStackTrace(); + } + return lists; + } + public List getBookingsRate(String rateCode, String roomType, String startDate, String endDate){ + EntityManager entity = this.factory.createEntityManager(); + List lists = new ArrayList<>(); + try { + StoredProcedureQuery store = entity.createNamedStoredProcedureQuery("getBookingsRate"); + store.setParameter("rate_code", rateCode); + store.setParameter("room_type", roomType); + store.setParameter("start_date", startDate); + store.setParameter("end_date", endDate); + lists = store.getResultList(); + entity.close(); + } catch (Exception e) { + entity.close(); + e.printStackTrace(); + } + return lists; + } + public List getBookingsByRoomNo(String roomNo){ + EntityManager entity = this.factory.createEntityManager(); + List lists = new ArrayList(); + try { + StoredProcedureQuery store = entity.createNamedStoredProcedureQuery("getBookingsByRoomNo"); + store.setParameter("room_no", roomNo); + lists = store.getResultList(); + entity.close(); + } catch (Exception e) { + entity.close(); + e.printStackTrace(); + } + List list = convertBookingList(lists); + return list; + } + public boolean checkDBConnection(){ + EntityManager entity = this.factory.createEntityManager(); + List lists = new ArrayList(); + boolean isConnect = false; + try { + StoredProcedureQuery store = entity.createNamedStoredProcedureQuery("checkDBConnection"); + lists = store.getResultList(); + if(lists.size()>0) isConnect = true; + entity.close(); + } catch (Exception e) { + entity.close(); + e.printStackTrace(); + } + return isConnect; + } + public List convertBookingList(List books){ + List bookings = new ArrayList(); + for(int i= 0 ;i convertBookingList_Optimize(List books){ + List bookings = new ArrayList(); + for(int i= 0 ;i getBookingCommentByCommentId(Long commentId,Integer resvNameId){ + EntityManager entity = this.factory.createEntityManager(); + List lists = new ArrayList<>(); + try { + StoredProcedureQuery store = entity.createNamedStoredProcedureQuery("GetOracleComment_OpenQuery"); + store.setParameter("commentId", commentId); + store.setParameter("resvNameId", resvNameId); + LogUtil.info(OperaDBBookingService.class,"Comment Id:"+commentId); + lists = store.getResultList(); + entity.close(); + } catch (Exception e) { + entity.close(); + e.printStackTrace(); + } + return lists; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/services/OperaService.java b/src/main/java/com/mgm/mcrm/booking/services/OperaService.java new file mode 100644 index 0000000..f334a33 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/services/OperaService.java @@ -0,0 +1,1242 @@ +package com.mgm.mcrm.booking.services; + +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import com.mgm.mcrm.booking.models.BookingsView; +import jakarta.annotation.Resource; +import javax.xml.XMLConstants; +import jakarta.xml.soap.SOAPMessage; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.gson.Gson; + +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.booking.dtos.opera.CancelBookingRequest; +import com.mgm.mcrm.booking.dtos.opera.CancelBookingResponse; +import com.mgm.mcrm.booking.dtos.opera.CombineShareRequest; +import com.mgm.mcrm.booking.dtos.opera.CombineShareResponse; +import com.mgm.mcrm.booking.dtos.opera.CreateBookingRequest; +import com.mgm.mcrm.booking.dtos.opera.CreateBookingResponse; +import com.mgm.mcrm.booking.dtos.opera.FetchBookingHotelReservation; +import com.mgm.mcrm.booking.dtos.opera.FetchBookingRequest; +import com.mgm.mcrm.booking.dtos.opera.FetchBookingResponse; +import com.mgm.mcrm.booking.dtos.opera.FetchBookingShareReservationDetails; +import com.mgm.mcrm.booking.dtos.opera.GuestRequestsRequest; +import com.mgm.mcrm.booking.dtos.opera.GuestRequestsResponse; +import com.mgm.mcrm.booking.dtos.opera.InsertGuestCardRequest; +import com.mgm.mcrm.booking.dtos.opera.InsertGuestCardResponse; +import com.mgm.mcrm.booking.dtos.opera.ModifyBookingRequest; +import com.mgm.mcrm.booking.dtos.opera.ModifyBookingResponse; +import com.mgm.mcrm.booking.models.OWSTransactions; +import com.mgm.mcrm.booking.dtos.opera.UpdatePassportRequest; +import com.mgm.mcrm.booking.dtos.opera.UpdatePassportResponse; +import com.mgm.mcrm.appsetting.services.SysSettingService; +import com.mgm.mcrm.common.utils.DateTimeUtil; +import com.mgm.mcrm.common.utils.LogUtil; +import com.mgm.mcrm.common.utils.SOAPUtil; +import com.mgm.mcrm.common.utils.XMLBuliderUtil; + + +@Service +public class OperaService { + public static final String OWS_Server="mgpmsdevows45"; //dev +// public static final String OWS_Server="mgpmsprdows45"; //prod + @Resource + private OWSTransactionsService owsTransService; + @Autowired + private SysSettingService settingService; + + public JSONObject guestRequests(GuestRequestsRequest obj) throws Exception { + boolean owsLog = settingService.isDBDbugLog(); + JSONObject objReturn = new JSONObject(); + + String returnStr = ""; + long spanTime = 0; + + StringBuffer sendSoapString = new StringBuffer(); + // get max id + OWSTransactions owsTrans = owsTransService.getOWSTransMaxId(); + int maxId = 0; + if (owsTrans != null) { + maxId = owsTrans.getId() + 1; + } + obj.setTransactionID(String.valueOf(maxId)); + String tempDate = DateTimeUtil.getCurrentDate("yyyy-MM-dd HH:mm:ss"); + String[] arrDate = StringUtils.split(tempDate, " "); + tempDate = arrDate[0] + "T" + arrDate[1]; + obj.setTimeStamp(tempDate); + sendSoapString = obj.getRequestString(); + Date startTime = new Date(); + Date endTime = new Date(); + + returnStr = SOAPUtil.getWebServiceSOAPUTF(SysCommon.apiConfig.getServerUrl_OWS() + "/OWS_WS_51/Reservation.asmx?wsdl", + "http://webservices.micros.com/ows/5.1/Reservation.wsdl#GuestRequests", sendSoapString); + LogUtil.info(OperaService.class, "[OperaService GuestRequests URL:]" + SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl http://webservices.micros.com/ows/5.1/Reservation.wsdl#GuestRequests"); + + endTime = new Date(); + spanTime = DateTimeUtil.getTimeSpanSSS(startTime, endTime); + if (StringUtils.isNotBlank(returnStr)) { + SOAPMessage soapMessage = SOAPUtil.getSOAPMessageFromXMLString(returnStr); + String bodyContent = ""; + DOMSource source = new DOMSource( + soapMessage.getSOAPBody().getElementsByTagName("GuestRequestsResponse").item(0)); + StringWriter stringResult = new StringWriter(); + TransformerFactory factory = TransformerFactory.newInstance(); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + //factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + ////factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); + factory.newTransformer().transform(source, new StreamResult(stringResult)); + bodyContent = stringResult.toString(); + GuestRequestsResponse resp = (GuestRequestsResponse) XMLBuliderUtil.toObject(GuestRequestsResponse.class, + bodyContent); + + if (resp.getResult().getResultStatusFlag().equals("SUCCESS")) { + objReturn.put("result_status", resp.getResult().getResultStatusFlag()); + } else { + objReturn = null; + } + + // save to db + owsTrans = new OWSTransactions(); + owsTrans.setService("Reservation"); + owsTrans.setAction("GuestRequests"); + owsTrans.setSuccess(resp.getResult().getResultStatusFlag().equals("SUCCESS") ? 1 : 0); + owsTrans.setExecuteTimeMs((int) spanTime); + owsTrans.setCreatedAt(endTime); + owsTrans.setUpdatedAt(endTime); + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + owsTrans.setUrlAction(SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl;http://webservices.micros.com/ows/5.1/Reservation.wsdl#GuestRequests"); + if (owsTrans.getSuccess() == 0) { + owsTrans.setErrorCode(resp.getResult().getOperaErrorCode()); + owsTrans.setErrorMessage(resp.getResult().getgDSError()); + } + if (owsLog) { + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + } else { + owsTrans.setRequest(null); + owsTrans.setResponse(null); + } + owsTransService.saveOWSTrans(owsTrans); + } + return objReturn; + } + + public JSONObject createBooking(CreateBookingRequest obj) throws Exception { + JSONObject booking = new JSONObject(); + boolean owsLog = settingService.isDBDbugLog();; + String returnStr = ""; + long spanTime = 0; + + StringBuffer sendSoapString = new StringBuffer(); + // get max id + OWSTransactions owsTrans = owsTransService.getOWSTransMaxId(); + int maxId = 0; + if (owsTrans != null) { + maxId = owsTrans.getId() + 1; + } + obj.setTransactionID(String.valueOf(maxId)); + String tempDate = DateTimeUtil.getCurrentDate("yyyy-MM-dd HH:mm:ss"); + String[] arrDate = StringUtils.split(tempDate, " "); + tempDate = arrDate[0] + "T" + arrDate[1]; + obj.setTimeStamp(tempDate); + sendSoapString = obj.getRequestString(); + + Gson gson = new Gson(); + LogUtil.info(OperaService.class, "[OperaService createBooking request string:]" + gson.toJson(sendSoapString)); + Date startTime = new Date(); + Date endTime = new Date(); + returnStr = SOAPUtil.getWebServiceSOAP(SysCommon.apiConfig.getServerUrl_OWS() + "/OWS_WS_51/Reservation.asmx?wsdl", + "http://webservices.micros.com/ows/5.1/Reservation.wsdl#CreateBooking", sendSoapString); + LogUtil.info(OperaService.class, "[OperaService CreateBooking URL:]" + SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl http://webservices.micros.com/ows/5.1/Reservation.wsdl#CreateBooking"); + endTime = new Date(); + spanTime = DateTimeUtil.getTimeSpanSSS(startTime, endTime); + if (StringUtils.isNotBlank(returnStr)) { + SOAPMessage soapMessage = SOAPUtil.getSOAPMessageFromXMLString(returnStr); + String bodyContent = ""; + DOMSource source = new DOMSource( + soapMessage.getSOAPBody().getElementsByTagName("CreateBookingResponse").item(0)); + StringWriter stringResult = new StringWriter(); + TransformerFactory factory = TransformerFactory.newInstance(); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + //factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + //factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); + factory.newTransformer().transform(source, new StreamResult(stringResult)); + bodyContent = XMLBuliderUtil.removeXmlPrefix(stringResult.toString(), new String[] { "r", "hc", "c" }); + CreateBookingResponse resp = (CreateBookingResponse) XMLBuliderUtil.toObject(CreateBookingResponse.class, + bodyContent); + + if (resp.getResult().getResultStatusFlag().equals("SUCCESS")) { + List uniqueIDList = resp.getHotelReservation().getUniqueIDList().getListUniqueID(); + String internalId = uniqueIDList.getFirst(); + String resvId = uniqueIDList.get(1); + String profileId = resp.getHotelReservation().getResGuests().getResGuest().getProfiles().getProfile() + .getProfileIDs().getUniqueID(); + String shortDes = resp.getHotelReservation().getRoomStays().getRoomStay().getRoomTypes().getRoomType() + .getRoomTypeDescription().getText(); + String total = resp.getHotelReservation().getRoomStays().getRoomStay().getTotal(); + + booking.put("internal_id", internalId); + booking.put("resv_id", resvId); + booking.put("profile_id", profileId); + booking.put("short_description", shortDes); + booking.put("total", total); + } else { + String errorCode = resp.getResult().getOperaErrorCode(); + if(Strings.CS.equals(resp.getResult().getOperaErrorCode(), "undefined")) + errorCode = "Connection Error"; + booking.put("message", getOWSError(errorCode)); + } + + // save to db + owsTrans = new OWSTransactions(); + owsTrans.setService("Reservation"); + owsTrans.setAction("CreateBooking"); + owsTrans.setSuccess(resp.getResult().getResultStatusFlag().equals("SUCCESS") ? 1 : 0); + owsTrans.setExecuteTimeMs((int) spanTime); + owsTrans.setCreatedAt(endTime); + owsTrans.setUpdatedAt(endTime); + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + owsTrans.setUrlAction(SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl;http://webservices.micros.com/ows/5.1/Reservation.wsdl#CreateBooking"); + if (owsTrans.getSuccess() == 0) { + owsTrans.setErrorCode(resp.getResult().getOperaErrorCode()); + owsTrans.setErrorMessage(resp.getResult().getgDSError()); + } + if (owsLog) { + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + } else { + owsTrans.setRequest(null); + owsTrans.setResponse(null); + } + owsTransService.saveOWSTrans(owsTrans); + + }else { + // save to db + owsTrans = new OWSTransactions(); + owsTrans.setService("Reservation"); + owsTrans.setAction("CreateBooking"); + owsTrans.setSuccess(0); + owsTrans.setExecuteTimeMs((int) spanTime); + owsTrans.setCreatedAt(endTime); + owsTrans.setUpdatedAt(endTime); + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + owsTrans.setUrlAction(SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl;http://webservices.micros.com/ows/5.1/Reservation.wsdl#CreateBooking"); + owsTrans.setErrorCode("400"); + owsTrans.setErrorMessage("Bad Request"); + if (owsLog) { + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + } else { + owsTrans.setRequest(null); + owsTrans.setResponse(null); + } + owsTransService.saveOWSTrans(owsTrans); + booking.put("message", "Reqeust Failed"); + } + + return booking; + } + + public JSONObject modifyBooking(ModifyBookingRequest obj) throws Exception { + JSONObject booking = new JSONObject(); + boolean owsLog = settingService.isDBDbugLog();; + String returnStr = ""; + long spanTime = 0; + + StringBuffer sendSoapString = new StringBuffer(); + // get max id + OWSTransactions owsTrans = owsTransService.getOWSTransMaxId(); + int maxId = 0; + if (owsTrans != null) { + maxId = owsTrans.getId() + 1; + } + obj.setTransactionID(String.valueOf(maxId)); + String tempDate = DateTimeUtil.getCurrentDate("yyyy-MM-dd HH:mm:ss"); + String[] arrDate = StringUtils.split(tempDate, " "); + tempDate = arrDate[0] + "T" + arrDate[1]; + obj.setTimeStamp(tempDate); + sendSoapString = obj.getRequestString(); + + Date startTime = new Date(); + Date endTime = new Date(); + returnStr = SOAPUtil.getWebServiceSOAP(SysCommon.apiConfig.getServerUrl_OWS() + "/OWS_WS_51/Reservation.asmx?wsdl", + "http://webservices.micros.com/ows/5.1/Reservation.wsdl#ModifyBooking", sendSoapString); + LogUtil.info(OperaService.class, "[OperaService modifyBooking URL:]" + SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl http://webservices.micros.com/ows/5.1/Reservation.wsdl#ModifyBooking"); + endTime = new Date(); + spanTime = DateTimeUtil.getTimeSpanSSS(startTime, endTime); + if (StringUtils.isNotBlank(returnStr)) { + SOAPMessage soapMessage = SOAPUtil.getSOAPMessageFromXMLString(returnStr); + String bodyContent = ""; + DOMSource source = new DOMSource( + soapMessage.getSOAPBody().getElementsByTagName("ModifyBookingResponse").item(0)); + StringWriter stringResult = new StringWriter(); + TransformerFactory factory = TransformerFactory.newInstance(); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + //factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + //factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); + factory.newTransformer().transform(source, new StreamResult(stringResult)); + bodyContent = XMLBuliderUtil.removeXmlPrefix(stringResult.toString(), new String[] { "r", "hc", "c" }); + ModifyBookingResponse resp = (ModifyBookingResponse) XMLBuliderUtil.toObject(ModifyBookingResponse.class, + bodyContent); + + if (resp.getResult().getResultStatusFlag().equals("SUCCESS")) { + List uniqueIDList = resp.getHotelReservation().getUniqueIDList().getListUniqueID(); + String internalId = uniqueIDList.get(0); + String resvId = uniqueIDList.get(1); + String profileId = resp.getHotelReservation().getResGuests().getResGuest().getProfiles().getProfile() + .getProfileIDs().getUniqueID(); + String shortDes = resp.getHotelReservation().getRoomStays().getRoomStay().getRoomTypes().getRoomType() + .getRoomTypeDescription().getText(); + String total = resp.getHotelReservation().getRoomStays().getRoomStay().getTotal(); + booking.put("internal_id", internalId); + booking.put("resv_id", resvId); + booking.put("profile_id", profileId); + booking.put("short_description", shortDes); + booking.put("total", total); + } else { + String errorCode = resp.getResult().getOperaErrorCode(); + if(Strings.CS.equals(resp.getResult().getOperaErrorCode(), "undefined")) + errorCode = "Connection Error"; + booking.put("message", getOWSError(errorCode)); + } + + // save to db + owsTrans = new OWSTransactions(); + owsTrans.setService("Reservation"); + owsTrans.setAction("ModifyBooking"); + owsTrans.setSuccess(resp.getResult().getResultStatusFlag().equals("SUCCESS") ? 1 : 0); + owsTrans.setExecuteTimeMs((int) spanTime); + owsTrans.setCreatedAt(endTime); + owsTrans.setUpdatedAt(endTime); + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + owsTrans.setUrlAction(SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl;http://webservices.micros.com/ows/5.1/Reservation.wsdl#ModifyBooking"); + if (owsTrans.getSuccess() == 0) { + owsTrans.setErrorCode(resp.getResult().getOperaErrorCode()); + owsTrans.setErrorMessage(resp.getResult().getgDSError()); + } + if (owsLog) { + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + } else { + owsTrans.setRequest(null); + owsTrans.setResponse(null); + } + owsTransService.saveOWSTrans(owsTrans); + + } + return booking; + } + + public JSONObject combineShare(CombineShareRequest obj) throws Exception { + boolean owsLog = settingService.isDBDbugLog();; + JSONObject objReturn = new JSONObject(); + + String returnStr = ""; + long spanTime = 0; + + StringBuffer sendSoapString = new StringBuffer(); + // get max id + OWSTransactions owsTrans = owsTransService.getOWSTransMaxId(); + int maxId = 0; + if (owsTrans != null) { + maxId = owsTrans.getId() + 1; + } + obj.setTransactionID(String.valueOf(maxId)); + String tempDate = DateTimeUtil.getCurrentDate("yyyy-MM-dd HH:mm:ss"); + String[] arrDate = StringUtils.split(tempDate, " "); + tempDate = arrDate[0] + "T" + arrDate[1]; + obj.setTimeStamp(tempDate); + sendSoapString = obj.getRequestString(); + + Date startTime = new Date(); + Date endTime = new Date(); + returnStr = SOAPUtil.getWebServiceSOAP(SysCommon.apiConfig.getServerUrl_OWS() + "/OWS_WS_51/Reservation.asmx?wsdl", + "http://webservices.micros.com/ows/5.1/Reservation.wsdl#CombineShare", sendSoapString); + LogUtil.info(OperaService.class, "[OperaService CombineShareRequest URL:]" + SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl http://webservices.micros.com/ows/5.1/Reservation.wsdl#CombineShare"); + + endTime = new Date(); + spanTime = DateTimeUtil.getTimeSpanSSS(startTime, endTime); + if (StringUtils.isNotBlank(returnStr)) { + SOAPMessage soapMessage = SOAPUtil.getSOAPMessageFromXMLString(returnStr); + String bodyContent = ""; + DOMSource source = new DOMSource( + soapMessage.getSOAPBody().getElementsByTagName("CombineShareResponse").item(0)); + StringWriter stringResult = new StringWriter(); + TransformerFactory factory = TransformerFactory.newInstance(); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + //factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + //factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); + factory.newTransformer().transform(source, new StreamResult(stringResult)); + bodyContent = stringResult.toString(); + CombineShareResponse resp = (CombineShareResponse) XMLBuliderUtil.toObject(CombineShareResponse.class, + bodyContent); + + if (resp.getResult().getResultStatusFlag().equals("SUCCESS")) { + objReturn.put("result_status", resp.getResult().getResultStatusFlag()); + } else { + objReturn = null; + } + + // save to db + owsTrans = new OWSTransactions(); + owsTrans.setService("Reservation"); + owsTrans.setAction("CombineShare"); + owsTrans.setSuccess(resp.getResult().getResultStatusFlag().equals("SUCCESS") ? 1 : 0); + owsTrans.setExecuteTimeMs((int) spanTime); + owsTrans.setCreatedAt(endTime); + owsTrans.setUpdatedAt(endTime); + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + owsTrans.setUrlAction(SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl;http://webservices.micros.com/ows/5.1/Reservation.wsdl#CombineShare"); + if (owsTrans.getSuccess() == 0) { + owsTrans.setErrorCode(resp.getResult().getOperaErrorCode()); + owsTrans.setErrorMessage(resp.getResult().getgDSError()); + } + if (owsLog) { + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + } else { + owsTrans.setRequest(null); + owsTrans.setResponse(null); + } + owsTransService.saveOWSTrans(owsTrans); + } + return objReturn; + } + + public JSONObject cancelBooking(CancelBookingRequest obj) throws Exception { + JSONObject booking = new JSONObject(); + boolean owsLog = settingService.isDBDbugLog();; + String returnStr = ""; + long spanTime = 0; + + StringBuffer sendSoapString = new StringBuffer(); + // get max id + OWSTransactions owsTrans = owsTransService.getOWSTransMaxId(); + int maxId = 0; + if (owsTrans != null) { + maxId = owsTrans.getId() + 1; + } + obj.setTransactionID(String.valueOf(maxId)); + String tempDate = DateTimeUtil.getCurrentDate("yyyy-MM-dd HH:mm:ss"); + String[] arrDate = StringUtils.split(tempDate, " "); + tempDate = arrDate[0] + "T" + arrDate[1]; + obj.setTimeStamp(tempDate); + sendSoapString = obj.getRequestString(); + + Gson gson = new Gson(); + LogUtil.info(OperaService.class, "[OperaService cancelBooking request string:]" + gson.toJson(sendSoapString)); + Date startTime = new Date(); + Date endTime = new Date(); + returnStr = SOAPUtil.getWebServiceSOAP(SysCommon.apiConfig.getServerUrl_OWS() + "/OWS_WS_51/Reservation.asmx?wsdl", + "http://webservices.micros.com/ows/5.1/Reservation.wsdl#CancelBooking", sendSoapString); + LogUtil.info(OperaService.class, "[OperaService CancelBooking URL:]" + "https://" + SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl http://webservices.micros.com/ows/5.1/Reservation.wsdl#CancelBooking"); + endTime = new Date(); + spanTime = DateTimeUtil.getTimeSpanSSS(startTime, endTime); + if (StringUtils.isNotBlank(returnStr)) { + + SOAPMessage soapMessage = SOAPUtil.getSOAPMessageFromXMLString(returnStr); + String bodyContent = ""; + DOMSource source = new DOMSource( + soapMessage.getSOAPBody().getElementsByTagName("CancelBookingResponse").item(0)); + StringWriter stringResult = new StringWriter(); + TransformerFactory factory = TransformerFactory.newInstance(); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + //factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + //factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); + factory.newTransformer().transform(source, new StreamResult(stringResult)); + bodyContent = XMLBuliderUtil.removeXmlPrefix(stringResult.toString(), new String[] { "r", "hc", "c" }); + CancelBookingResponse resp = (CancelBookingResponse) XMLBuliderUtil.toObject(CancelBookingResponse.class, + bodyContent); + + if (resp.getResult().getResultStatusFlag().equals("SUCCESS")) { + booking.put("result_status", true); + } else { + booking = null; + } + + // save to db + owsTrans = new OWSTransactions(); + owsTrans.setService("Reservation"); + owsTrans.setAction("CancelBooking"); + owsTrans.setSuccess(resp.getResult().getResultStatusFlag().equals("SUCCESS") ? 1 : 0); + owsTrans.setExecuteTimeMs((int) spanTime); + owsTrans.setCreatedAt(endTime); + owsTrans.setUpdatedAt(endTime); + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + owsTrans.setUrlAction(SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl;http://webservices.micros.com/ows/5.1/Reservation.wsdl#CancelBooking"); + if (owsTrans.getSuccess() == 0) { + owsTrans.setErrorCode(resp.getResult().getOperaErrorCode()); + owsTrans.setErrorMessage(resp.getResult().getgDSError()); + } + if (owsLog) { + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + } else { + owsTrans.setRequest(null); + owsTrans.setResponse(null); + } + owsTransService.saveOWSTrans(owsTrans); + }else { + // save to db + owsTrans = new OWSTransactions(); + owsTrans.setService("Reservation"); + owsTrans.setAction("CancelBooking"); + owsTrans.setSuccess(0); + owsTrans.setExecuteTimeMs((int) spanTime); + owsTrans.setCreatedAt(endTime); + owsTrans.setUpdatedAt(endTime); + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + owsTrans.setUrlAction(SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl;http://webservices.micros.com/ows/5.1/Reservation.wsdl#CancelBooking"); + owsTrans.setErrorCode("400"); + owsTrans.setErrorMessage("Bad Request"); + if (owsLog) { + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + } else { + owsTrans.setRequest(null); + owsTrans.setResponse(null); + } + owsTransService.saveOWSTrans(owsTrans); + booking.put("message", "Reqeust Failed"); + } + + return booking; + + } + + public JSONObject insertGuestCard(InsertGuestCardRequest obj) throws Exception { + JSONObject objReturn = new JSONObject(); + boolean owsLog = settingService.isDBDbugLog();; + String returnStr = ""; + long spanTime = 0; + + StringBuffer sendSoapString = new StringBuffer(); + // get max id + OWSTransactions owsTrans = owsTransService.getOWSTransMaxId(); + int maxId = 0; + if (owsTrans != null) { + maxId = owsTrans.getId() + 1; + } + obj.setTransactionID(String.valueOf(maxId)); + String tempDate = DateTimeUtil.getCurrentDate("yyyy-MM-dd HH:mm:ss"); + String[] arrDate = StringUtils.split(tempDate, " "); + tempDate = arrDate[0] + "T" + arrDate[1]; + obj.setTimeStamp(tempDate); + sendSoapString = obj.getRequestString(); + + Date startTime = new Date(); + Date endTime = new Date(); + returnStr = SOAPUtil.getWebServiceSOAP(SysCommon.apiConfig.getServerUrl_OWS() + "/OWS_WS_51/Name.asmx?wsdl", + "http://webservices.micros.com/ows/5.1/Name.wsdl#InsertGuestCard", sendSoapString); + LogUtil.info(OperaService.class, "[OperaService insertGustCard URL:]" + SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Name.asmx?wsdl http://webservices.micros.com/ows/5.1/Name.wsdl#InsertGuestCard"); + endTime = new Date(); + spanTime = DateTimeUtil.getTimeSpanSSS(startTime, endTime); + if (StringUtils.isNotBlank(returnStr)) { + + SOAPMessage soapMessage = SOAPUtil.getSOAPMessageFromXMLString(returnStr); + String bodyContent = ""; + DOMSource source = new DOMSource( + soapMessage.getSOAPBody().getElementsByTagName("InsertGuestCardResponse").item(0)); + StringWriter stringResult = new StringWriter(); + TransformerFactory factory = TransformerFactory.newInstance(); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + //factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + //factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); + factory.newTransformer().transform(source, new StreamResult(stringResult)); + bodyContent = XMLBuliderUtil.removeXmlPrefix(stringResult.toString(), new String[] { "r", "hc", "c" }); + InsertGuestCardResponse resp = (InsertGuestCardResponse) XMLBuliderUtil.toObject(InsertGuestCardResponse.class, + bodyContent); + + if (resp.getResult().getResultStatusFlag().equals("SUCCESS")) { + objReturn.put("result_status", true); + } else { + objReturn = null; + } + + // save to db + owsTrans = new OWSTransactions(); + owsTrans.setService("Name"); + owsTrans.setAction("InsertGuestCard"); + owsTrans.setSuccess(resp.getResult().getResultStatusFlag().equals("SUCCESS") ? 1 : 0); + owsTrans.setExecuteTimeMs((int) spanTime); + owsTrans.setCreatedAt(endTime); + owsTrans.setUpdatedAt(endTime); + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + owsTrans.setUrlAction(SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Name.asmx?wsdl;http://webservices.micros.com/ows/5.1/Name.wsdl#InsertGuestCard"); + if (owsTrans.getSuccess() == 0) { + owsTrans.setErrorCode(resp.getResult().getOperaErrorCode()); + owsTrans.setErrorMessage(resp.getResult().getgDSError()); + } + if (owsLog) { + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + } else { + owsTrans.setRequest(null); + owsTrans.setResponse(null); + } + owsTransService.saveOWSTrans(owsTrans); + }else { + // save to db + owsTrans = new OWSTransactions(); + owsTrans.setService("Name"); + owsTrans.setAction("InsertGuestCard"); + owsTrans.setSuccess(0); + owsTrans.setExecuteTimeMs((int) spanTime); + owsTrans.setCreatedAt(endTime); + owsTrans.setUpdatedAt(endTime); + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + owsTrans.setUrlAction(SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Name.asmx?wsdl;http://webservices.micros.com/ows/5.1/Name.wsdl#InsertGuestCard"); + owsTrans.setErrorCode("400"); + owsTrans.setErrorMessage("Bad Request"); + if (owsLog) { + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + } else { + owsTrans.setRequest(null); + owsTrans.setResponse(null); + } + owsTransService.saveOWSTrans(owsTrans); + objReturn.put("message", "Reqeust Failed"); + } + + return objReturn; + } + + public JSONObject updatePassport(UpdatePassportRequest obj) throws Exception { + JSONObject objReturn = new JSONObject(); + boolean owsLog = settingService.isDBDbugLog();; + String returnStr = ""; + long spanTime = 0; + + StringBuffer sendSoapString = new StringBuffer(); + // get max id + OWSTransactions owsTrans = owsTransService.getOWSTransMaxId(); + int maxId = 0; + if (owsTrans != null) { + maxId = owsTrans.getId() + 1; + } + obj.setTransactionID(String.valueOf(maxId)); + String tempDate = DateTimeUtil.getCurrentDate("yyyy-MM-dd HH:mm:ss"); + String[] arrDate = StringUtils.split(tempDate, " "); + tempDate = arrDate[0] + "T" + arrDate[1]; + obj.setTimeStamp(tempDate); + sendSoapString = obj.getRequestString(); + + Date startTime = new Date(); + Date endTime = new Date(); + returnStr = SOAPUtil.getWebServiceSOAP(SysCommon.apiConfig.getServerUrl_OWS() + "/OWS_WS_51/Name.asmx?wsdl", + "http://webservices.micros.com/ows/5.1/Name.wsdl#UpdatePassport", sendSoapString); + LogUtil.info(OperaService.class, "[OperaService UpdatePassport URL:]" + SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Name.asmx?wsdl http://webservices.micros.com/ows/5.1/Name.wsdl#UpdatePassport"); + endTime = new Date(); + spanTime = DateTimeUtil.getTimeSpanSSS(startTime, endTime); + if (StringUtils.isNotBlank(returnStr)) { + + SOAPMessage soapMessage = SOAPUtil.getSOAPMessageFromXMLString(returnStr); + String bodyContent = ""; + DOMSource source = new DOMSource( + soapMessage.getSOAPBody().getElementsByTagName("UpdatePassportResponse").item(0)); + StringWriter stringResult = new StringWriter(); + TransformerFactory factory = TransformerFactory.newInstance(); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + //factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + //factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); + factory.newTransformer().transform(source, new StreamResult(stringResult)); + bodyContent = XMLBuliderUtil.removeXmlPrefix(stringResult.toString(), new String[] { "r", "hc", "c" }); + UpdatePassportResponse resp = (UpdatePassportResponse) XMLBuliderUtil.toObject(UpdatePassportResponse.class, + bodyContent); + + if (resp.getResult().getResultStatusFlag().equals("SUCCESS")) { + objReturn.put("result_status", true); + } else { + objReturn = null; + } + + // save to db + owsTrans = new OWSTransactions(); + owsTrans.setService("Name"); + owsTrans.setAction("UpdatePassport"); + owsTrans.setSuccess(resp.getResult().getResultStatusFlag().equals("SUCCESS") ? 1 : 0); + owsTrans.setExecuteTimeMs((int) spanTime); + owsTrans.setCreatedAt(endTime); + owsTrans.setUpdatedAt(endTime); + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + owsTrans.setUrlAction(SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Name.asmx?wsdl;http://webservices.micros.com/ows/5.1/Name.wsdl#UpdatePassport"); + if (owsTrans.getSuccess() == 0) { + owsTrans.setErrorCode(resp.getResult().getOperaErrorCode()); + owsTrans.setErrorMessage(resp.getResult().getgDSError()); + } + if (owsLog) { + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + } else { + owsTrans.setRequest(null); + owsTrans.setResponse(null); + } + owsTransService.saveOWSTrans(owsTrans); + }else { + // save to db + owsTrans = new OWSTransactions(); + owsTrans.setService("Name"); + owsTrans.setAction("UpdatePassport"); + owsTrans.setSuccess(0); + owsTrans.setExecuteTimeMs((int) spanTime); + owsTrans.setCreatedAt(endTime); + owsTrans.setUpdatedAt(endTime); + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + owsTrans.setUrlAction(SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Name.asmx?wsdl;http://webservices.micros.com/ows/5.1/Name.wsdl#UpdatePassport"); + owsTrans.setErrorCode("400"); + owsTrans.setErrorMessage("Bad Request"); + if (owsLog) { + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + } else { + owsTrans.setRequest(null); + owsTrans.setResponse(null); + } + owsTransService.saveOWSTrans(owsTrans); + objReturn.put("message", "Reqeust Failed"); + } + + return objReturn; + } + + public JSONObject modifyETA(ModifyBookingRequest obj) throws Exception { + JSONObject booking = new JSONObject(); + boolean owsLog = settingService.isDBDbugLog();; + String returnStr = ""; + long spanTime = 0; + + StringBuffer sendSoapString = new StringBuffer(); + // get max id + OWSTransactions owsTrans = owsTransService.getOWSTransMaxId(); + int maxId = 0; + if (owsTrans != null) { + maxId = owsTrans.getId() + 1; + } + obj.setTransactionID(String.valueOf(maxId)); + String tempDate = DateTimeUtil.getCurrentDate("yyyy-MM-dd HH:mm:ss"); + String[] arrDate = StringUtils.split(tempDate, " "); + tempDate = arrDate[0] + "T" + arrDate[1]; + obj.setTimeStamp(tempDate); + sendSoapString = obj.getRequestETAString(); + + Date startTime = new Date(); + Date endTime = new Date(); + returnStr = SOAPUtil.getWebServiceSOAP(SysCommon.apiConfig.getServerUrl_OWS() + "/OWS_WS_51/Reservation.asmx?wsdl", + "http://webservices.micros.com/ows/5.1/Reservation.wsdl#ModifyBooking", sendSoapString); + LogUtil.info(OperaService.class, "[OperaService modifyBooking URL:]" + SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl http://webservices.micros.com/ows/5.1/Reservation.wsdl#ModifyBooking"); + endTime = new Date(); + spanTime = DateTimeUtil.getTimeSpanSSS(startTime, endTime); + if (StringUtils.isNotBlank(returnStr)) { + SOAPMessage soapMessage = SOAPUtil.getSOAPMessageFromXMLString(returnStr); + String bodyContent = ""; + DOMSource source = new DOMSource( + soapMessage.getSOAPBody().getElementsByTagName("ModifyBookingResponse").item(0)); + StringWriter stringResult = new StringWriter(); + TransformerFactory factory = TransformerFactory.newInstance(); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + factory.newTransformer().transform(source, new StreamResult(stringResult)); + bodyContent = XMLBuliderUtil.removeXmlPrefix(stringResult.toString(), new String[] { "r", "hc", "c" }); + ModifyBookingResponse resp = (ModifyBookingResponse) XMLBuliderUtil.toObject(ModifyBookingResponse.class, + bodyContent); + + if (resp.getResult().getResultStatusFlag().equals("SUCCESS")) { + List uniqueIDList = resp.getHotelReservation().getUniqueIDList().getListUniqueID(); + String internalId = uniqueIDList.getFirst(); + String resvId = uniqueIDList.get(1); + booking.put("internal_id", internalId); + booking.put("resv_id", resvId); + } else { + String errorCode = resp.getResult().getOperaErrorCode(); + if(Strings.CS.equals(resp.getResult().getOperaErrorCode(), "undefined")) + errorCode = "Connection Error"; + booking.put("message", getOWSError(errorCode)); + } + + // save to db + owsTrans = new OWSTransactions(); + owsTrans.setService("Reservation"); + owsTrans.setAction("ModifyETA"); + owsTrans.setSuccess(resp.getResult().getResultStatusFlag().equals("SUCCESS") ? 1 : 0); + owsTrans.setExecuteTimeMs((int) spanTime); + owsTrans.setCreatedAt(endTime); + owsTrans.setUpdatedAt(endTime); + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + owsTrans.setUrlAction(SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl;http://webservices.micros.com/ows/5.1/Reservation.wsdl#ModifyBooking"); + if (owsTrans.getSuccess() == 0) { + owsTrans.setErrorCode(resp.getResult().getOperaErrorCode()); + owsTrans.setErrorMessage(resp.getResult().getgDSError()); + } + if (owsLog) { + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + } else { + owsTrans.setRequest(null); + owsTrans.setResponse(null); + } + owsTransService.saveOWSTrans(owsTrans); + + }else { + // save to db + owsTrans = new OWSTransactions(); + owsTrans.setService("Reservation"); + owsTrans.setAction("ModifyETA"); + owsTrans.setSuccess(0); + owsTrans.setExecuteTimeMs((int) spanTime); + owsTrans.setCreatedAt(endTime); + owsTrans.setUpdatedAt(endTime); + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + owsTrans.setUrlAction(SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl;http://webservices.micros.com/ows/5.1/Reservation.wsdl#ModifyBooking"); + if (owsTrans.getSuccess() == 0) { + owsTrans.setErrorCode("400"); + owsTrans.setErrorMessage("Bad Request"); + } + if (owsLog) { + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + } else { + owsTrans.setRequest(null); + owsTrans.setResponse(null); + } + owsTransService.saveOWSTrans(owsTrans); + } + return booking; + } + + public JSONObject changeBookingDate(ModifyBookingRequest obj) throws Exception { + JSONObject booking = new JSONObject(); + boolean owsLog = settingService.isDBDbugLog();; + String returnStr = ""; + long spanTime = 0; + + StringBuffer sendSoapString = new StringBuffer(); + // get max id + OWSTransactions owsTrans = owsTransService.getOWSTransMaxId(); + int maxId = 0; + if (owsTrans != null) { + maxId = owsTrans.getId() + 1; + } + obj.setTransactionID(String.valueOf(maxId)); + String tempDate = DateTimeUtil.getCurrentDate("yyyy-MM-dd HH:mm:ss"); + String[] arrDate = StringUtils.split(tempDate, " "); + tempDate = arrDate[0] + "T" + arrDate[1]; + obj.setTimeStamp(tempDate); + sendSoapString = obj.getRequestChangeDateString(); + + Date startTime = new Date(); + Date endTime = new Date(); + returnStr = SOAPUtil.getWebServiceSOAP(SysCommon.apiConfig.getServerUrl_OWS() + "/OWS_WS_51/Reservation.asmx?wsdl", + "http://webservices.micros.com/ows/5.1/Reservation.wsdl#ModifyBooking", sendSoapString); + LogUtil.info(OperaService.class, "[OperaService modifyBooking URL:]" + SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl http://webservices.micros.com/ows/5.1/Reservation.wsdl#ModifyBooking"); + endTime = new Date(); + spanTime = DateTimeUtil.getTimeSpanSSS(startTime, endTime); + if (StringUtils.isNotBlank(returnStr)) { + SOAPMessage soapMessage = SOAPUtil.getSOAPMessageFromXMLString(returnStr); + String bodyContent = ""; + DOMSource source = new DOMSource( + soapMessage.getSOAPBody().getElementsByTagName("ModifyBookingResponse").item(0)); + StringWriter stringResult = new StringWriter(); + TransformerFactory factory = TransformerFactory.newInstance(); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + //factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + //factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); + factory.newTransformer().transform(source, new StreamResult(stringResult)); + bodyContent = XMLBuliderUtil.removeXmlPrefix(stringResult.toString(), new String[] { "r", "hc", "c" }); + ModifyBookingResponse resp = (ModifyBookingResponse) XMLBuliderUtil.toObject(ModifyBookingResponse.class, + bodyContent); + + if (resp.getResult().getResultStatusFlag().equals("SUCCESS")) { + List uniqueIDList = resp.getHotelReservation().getUniqueIDList().getListUniqueID(); + String internalId = uniqueIDList.get(0); + String resvId = uniqueIDList.get(1); + String profileId = resp.getHotelReservation().getResGuests().getResGuest().getProfiles().getProfile() + .getProfileIDs().getUniqueID(); + String shortDes = resp.getHotelReservation().getRoomStays().getRoomStay().getRoomTypes().getRoomType() + .getRoomTypeDescription().getText(); + String total = resp.getHotelReservation().getRoomStays().getRoomStay().getTotal(); + booking.put("internal_id", internalId); + booking.put("resv_id", resvId); + booking.put("profile_id", profileId); + booking.put("short_description", shortDes); + booking.put("total", total); + } else { + String errorCode = resp.getResult().getOperaErrorCode(); + if(Strings.CS.equals(resp.getResult().getOperaErrorCode(), "undefined")) + errorCode = "Connection Error"; + booking.put("message", getOWSError(errorCode)); + } + + // save to db + owsTrans = new OWSTransactions(); + owsTrans.setService("Reservation"); + owsTrans.setAction("ChangeBookingDate"); + owsTrans.setSuccess(resp.getResult().getResultStatusFlag().equals("SUCCESS") ? 1 : 0); + owsTrans.setExecuteTimeMs((int) spanTime); + owsTrans.setCreatedAt(endTime); + owsTrans.setUpdatedAt(endTime); + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + owsTrans.setUrlAction(SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl;http://webservices.micros.com/ows/5.1/Reservation.wsdl#ModifyBooking"); + if (owsTrans.getSuccess() == 0) { + owsTrans.setErrorCode(resp.getResult().getOperaErrorCode()); + owsTrans.setErrorMessage(resp.getResult().getgDSError()); + } + if (owsLog) { + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + } else { + owsTrans.setRequest(null); + owsTrans.setResponse(null); + } + owsTransService.saveOWSTrans(owsTrans); + + } + return booking; + } + + public JSONObject fetchBooking(FetchBookingRequest obj) throws Exception { + boolean owsLog = settingService.isDBDbugLog(); + JSONObject objReturn = new JSONObject(); + + String returnStr = ""; + long spanTime = 0; + + StringBuffer sendSoapString = new StringBuffer(); + // get max id + OWSTransactions owsTrans = owsTransService.getOWSTransMaxId(); + int maxId = 0; + if (owsTrans != null) { + maxId = owsTrans.getId() + 1; + } + obj.setTransactionID(String.valueOf(maxId)); + String tempDate = DateTimeUtil.getCurrentDate("yyyy-MM-dd HH:mm:ss"); + String[] arrDate = StringUtils.split(tempDate, " "); + tempDate = arrDate[0] + "T" + arrDate[1]; + obj.setTimeStamp(tempDate); + sendSoapString = obj.getRequestString(); + Date startTime = new Date(); + Date endTime = new Date(); + + returnStr = SOAPUtil.getWebServiceSOAP(SysCommon.apiConfig.getServerUrl_OWS() + "/OWS_WS_51/Reservation.asmx?wsdl", + "http://webservices.micros.com/ows/5.1/Reservation.wsdl#FetchBooking", sendSoapString); + + LogUtil.info(OperaService.class, "[OperaService getFetchBooking URL:]" + SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl http://webservices.micros.com/ows/5.1/Reservation.wsdl#FetchBooking"); + + //returnStr = obj.getResponseString(); + + endTime = new Date(); + spanTime = DateTimeUtil.getTimeSpanSSS(startTime, endTime); + if (StringUtils.isNotBlank(returnStr)) { + SOAPMessage soapMessage = SOAPUtil.getSOAPMessageFromXMLString(returnStr); + String bodyContent = ""; + DOMSource source = new DOMSource( + soapMessage.getSOAPBody().getElementsByTagName("FetchBookingResponse").item(0)); + StringWriter stringResult = new StringWriter(); + TransformerFactory factory = TransformerFactory.newInstance(); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + //factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + //factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); + factory.newTransformer().transform(source, new StreamResult(stringResult)); + + bodyContent = XMLBuliderUtil.removeXmlPrefix(stringResult.toString(), new String[] { "r", "hc", "c" }); + + + FetchBookingResponse resp = (FetchBookingResponse) XMLBuliderUtil.toObject(FetchBookingResponse.class, + bodyContent); + + + if (resp.getResult().getResultStatusFlag().equals("SUCCESS")) { + FetchBookingHotelReservation hotel = resp.getHotelReservation(); + //share confirmation no + if( hotel.getShareReservations()!=null) { + if(hotel.getShareReservations().getShareReservationDetails()!=null) { + List shareDetail = + (List)(hotel.getShareReservations().getShareReservationDetails()); + List shareConfList = new ArrayList<>(); + for (int i = 0; i < shareDetail.size(); i++) { + FetchBookingShareReservationDetails details = shareDetail.get(i); + String shareConfNo = details.getUniqueIDList().getListUniqueID().getFirst(); + if(!Strings.CS.equals(shareConfNo, obj.getConfirmationNo())) { + shareConfList.add(shareConfNo); + } + } + if(shareConfList.size()>0) { + objReturn.put("shareConfList", shareConfList); + } + } + } + } + + // save to db + owsTrans = new OWSTransactions(); + owsTrans.setService("Reservation"); + owsTrans.setAction("FetchBooking"); + owsTrans.setSuccess(resp.getResult().getResultStatusFlag().equals("SUCCESS") ? 1 : 0); + owsTrans.setExecuteTimeMs((int) spanTime); + owsTrans.setCreatedAt(endTime); + owsTrans.setUpdatedAt(endTime); + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + owsTrans.setUrlAction(SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl;http://webservices.micros.com/ows/5.1/Reservation.wsdl#FetchBooking"); + if (owsTrans.getSuccess() == 0) { + owsTrans.setErrorCode(resp.getResult().getOperaErrorCode()); + owsTrans.setErrorMessage(resp.getResult().getgDSError()); + } + if (owsLog) { + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + } else { + owsTrans.setRequest(null); + owsTrans.setResponse(null); + } + owsTransService.saveOWSTrans(owsTrans); + } + return objReturn; + } + + + public String getOWSError(String error) throws Exception { + String msg = error; + if(Strings.CS.contains(msg, "INVALID_PROMOTION_CODE")) { + msg = "OWS Error: Promotion code not ready, please contact MSC."; + } else if(Strings.CS.contains(msg, "ROOM_UNAVAILABLE")) { + msg = "OWS Error: No available room, please contact MSC."; + }else { + msg = "OWS Error: "+msg; + } + return msg; + } + + public String makeCashierComment(BookingsView book) { + String comment = ""; + String checkinDate = DateTimeUtil.getDateByFormat(book.getCheckinDate(), "dd"); + String smonth = DateTimeUtil.getDateByFormat(book.getCheckinDate(), "MMM"); + String lmonth = DateTimeUtil.getDateByFormat(book.getCheckoutDate(), "MMM"); + String dateRange = ""; + + if(book.getNumOfNight() == 1) { + dateRange = checkinDate + " " + smonth; + } else { + String stayDate = DateTimeUtil.getDateByFormat(DateTimeUtil.addDay(book.getCheckoutDate(), -1), "dd"); + String stayMonth = DateTimeUtil.getDateByFormat(DateTimeUtil.addDay(book.getCheckoutDate(), -1), "MMM"); + + if(Strings.CS.equals(smonth, stayMonth)) { + dateRange = checkinDate + "-" + stayDate + " " + smonth; + } else { + dateRange = checkinDate + " " + smonth + "-" + stayDate + " " + stayMonth; + } + } + if(Strings.CS.equals(book.getBookingTypeName(), "IM")) { + comment = "GOA/TBA..APP"; + String dateList = book.getDateLists(); + JSONArray dateLists = JSONArray.parseArray(dateList); + JSONObject date = (JSONObject) dateLists.getFirst(); + String subComment = ""; + if(date.containsKey("isPost")&&date.containsKey("depositType")) { + if(date.getInteger("depositType")==0) { + subComment = "[WAIVE DEPOSIT AND "; + }else { + subComment = "[COLLECT DEPOSIT AND "; + } + if(date.getInteger("isPost")==0) { + subComment += "NO POST]"; + }else { + subComment += "YES POST]"; + } + subComment += "..APP"; + } + if(date.containsKey("isPost")&&!date.containsKey("depositType")) { + if(date.getInteger("isPost")==0) { + subComment += "[NO POST]"; + }else { + subComment += "[YES POST]"; + } + subComment += "..APP"; + } + if(!date.containsKey("isPost")&&date.containsKey("depositType")) { + if(date.getInteger("depositType")==0) { + subComment = "[WAIVE DEPOSIT]"; + }else { + subComment = "[COLLECT DEPOSIT]"; + } + subComment += "..APP"; + } + if(!StringUtils.isEmpty(subComment)) { + comment+=(" "+subComment); + } + }else { + comment = String.format("(RM) COMP..APP %s,%s,%s", dateRange, + book.getDlSourceId(), book.getCreatedBy()); + } + + return comment; + } + + public String makeChangeDateComment(Bookings book) { + String comment = ""; + String checkinDate = DateTimeUtil.getDateByFormat(book.getCheckinDate(), "dd MMM"); + String checkoutDate = DateTimeUtil.getDateByFormat(book.getCheckoutDate(), "dd MMM"); + comment = String.format("AMEND C/I ON %s AND C/O ON %s VIA APP",checkinDate,checkoutDate); + + return comment; + } + + public JSONObject modifyMiscCharge(ModifyBookingRequest obj)throws Exception{ + JSONObject booking = new JSONObject(); + Boolean owsLog = settingService.isDBDbugLog();; + String returnStr = ""; + long spanTime = 0; + + StringBuffer sendSoapString = new StringBuffer(); + // get max id + OWSTransactions owsTrans = owsTransService.getOWSTransMaxId(); + int maxId = 0; + if (owsTrans != null) { + maxId = owsTrans.getId() + 1; + } + obj.setTransactionID(String.valueOf(maxId)); + String tempDate = DateTimeUtil.getCurrentDate("yyyy-MM-dd HH:mm:ss"); + String[] arrDate = StringUtils.split(tempDate, " "); + tempDate = arrDate[0] + "T" + arrDate[1]; + obj.setTimeStamp(tempDate); + sendSoapString = obj.getRequestMisChargeString(); + + Date startTime = new Date(); + Date endTime = new Date(); + returnStr = SOAPUtil.getWebServiceSOAP(SysCommon.apiConfig.getServerUrl_OWS() + "/OWS_WS_51/Reservation.asmx?wsdl", + "http://webservices.micros.com/ows/5.1/Reservation.wsdl#ModifyBooking", sendSoapString); + LogUtil.info(OperaService.class, "[OperaService modifyBooking URL:]" + SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl http://webservices.micros.com/ows/5.1/Reservation.wsdl#ModifyBooking"); + endTime = new Date(); + spanTime = DateTimeUtil.getTimeSpanSSS(startTime, endTime); + if (StringUtils.isNotBlank(returnStr)) { + SOAPMessage soapMessage = SOAPUtil.getSOAPMessageFromXMLString(returnStr); + String bodyContent = ""; + DOMSource source = new DOMSource( + soapMessage.getSOAPBody().getElementsByTagName("ModifyBookingResponse").item(0)); + StringWriter stringResult = new StringWriter(); + TransformerFactory factory = TransformerFactory.newInstance(); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + factory.newTransformer().transform(source, new StreamResult(stringResult)); + bodyContent = XMLBuliderUtil.removeXmlPrefix(stringResult.toString(), new String[] { "r", "hc", "c" }); + ModifyBookingResponse resp = (ModifyBookingResponse) XMLBuliderUtil.toObject(ModifyBookingResponse.class, + bodyContent); + + if (resp.getResult().getResultStatusFlag().equals("SUCCESS")) { + List uniqueIDList = resp.getHotelReservation().getUniqueIDList().getListUniqueID(); + String internalId = uniqueIDList.get(0); + String resvId = uniqueIDList.get(1); + booking.put("internal_id", internalId); + booking.put("resv_id", resvId); + } else { + String errorCode = resp.getResult().getOperaErrorCode(); + if(StringUtils.equals(resp.getResult().getOperaErrorCode(), "undefined")) + errorCode = "Connection Error"; + booking.put("message", getOWSError(errorCode)); + } + + // save to db + owsTrans = new OWSTransactions(); + owsTrans.setService("Reservation"); + owsTrans.setAction("ModifyMisCharge"); + owsTrans.setSuccess(resp.getResult().getResultStatusFlag().equals("SUCCESS") ? 1 : 0); + owsTrans.setExecuteTimeMs((int) spanTime); + owsTrans.setCreatedAt(endTime); + owsTrans.setUpdatedAt(endTime); + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + owsTrans.setUrlAction(SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl;http://webservices.micros.com/ows/5.1/Reservation.wsdl#ModifyBooking"); + if (owsTrans.getSuccess() == 0) { + owsTrans.setErrorCode(resp.getResult().getOperaErrorCode()); + owsTrans.setErrorMessage(resp.getResult().getgDSError()); + } + if (owsLog) { + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + } else { + owsTrans.setRequest(null); + owsTrans.setResponse(null); + } + owsTransService.saveOWSTrans(owsTrans); + + }else { + // save to db + owsTrans = new OWSTransactions(); + owsTrans.setService("Reservation"); + owsTrans.setAction("ModifyETA"); + owsTrans.setSuccess(0); + owsTrans.setExecuteTimeMs((int) spanTime); + owsTrans.setCreatedAt(endTime); + owsTrans.setUpdatedAt(endTime); + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + owsTrans.setUrlAction(SysCommon.apiConfig.getServerUrl_OWS() + + "/OWS_WS_51/Reservation.asmx?wsdl;http://webservices.micros.com/ows/5.1/Reservation.wsdl#ModifyBooking"); + if (owsTrans.getSuccess() == 0) { + owsTrans.setErrorCode("400"); + owsTrans.setErrorMessage("Bad Request"); + } + if (owsLog) { + owsTrans.setRequest(sendSoapString.toString()); + owsTrans.setResponse(returnStr); + } else { + owsTrans.setRequest(null); + owsTrans.setResponse(null); + } + owsTransService.saveOWSTrans(owsTrans); + } + return booking; + } +} diff --git a/src/main/java/com/mgm/mcrm/booking/services/WaitlistBookingService.java b/src/main/java/com/mgm/mcrm/booking/services/WaitlistBookingService.java new file mode 100644 index 0000000..7b4275f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/services/WaitlistBookingService.java @@ -0,0 +1,709 @@ +package com.mgm.mcrm.booking.services; + +import java.util.*; + +import com.mgm.mcrm.allotment.models.CfgAppChannel; +import com.mgm.mcrm.allotment.models.CfgOtherAllotment; +import com.mgm.mcrm.allotment.models.CfgOtherAppChannel; +import com.mgm.mcrm.allotment.models.CfgRoomCriterias; +import com.mgm.mcrm.allotment.repositories.OtherAllotmentDao; +import com.mgm.mcrm.appsetting.models.CfgSettings; +import com.mgm.mcrm.appsetting.services.SettingService; +import com.mgm.mcrm.authorization.dtos.LoginUserInfo; +import com.mgm.mcrm.authorization.services.MgmUserService; +import com.mgm.mcrm.basesetting.property.models.CfgProperties; +import com.mgm.mcrm.basesetting.property.repositories.PropertyDao; +import com.mgm.mcrm.booking.dtos.BookingDto; +import com.mgm.mcrm.booking.mappers.BookingMapper; +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.booking.models.BookingsView; +import com.mgm.mcrm.booking.models.GamingData; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.common.dtos.EumnApprovalStatus; +import com.mgm.mcrm.common.services.MGMApiService; +import com.mgm.mcrm.notification.models.Email; +import com.mgm.mcrm.player.services.PlayerService; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.parser.Feature; +import com.google.gson.Gson; + +import com.mgm.mcrm.common.utils.DateTimeUtil; +import com.mgm.mcrm.common.utils.LogUtil; +import com.mgm.mcrm.common.utils.SendEmail; +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.constants.SysConstants; +import com.mgm.mcrm.booking.repositories.BookingDao; +import com.mgm.mcrm.booking.repositories.BookingViewDao; +import com.mgm.mcrm.notification.repositories.EmailDao; +import com.mgm.mcrm.booking.repositories.GamingDataDao; +import com.mgm.mcrm.basesetting.room.repositories.OtherRoomStatusDao; +import com.mgm.mcrm.allotment.repositories.RoomCriteriaDao; +import com.mgm.mcrm.common.jms.BookingControlMsgSender; + +import com.mgm.mcrm.common.dtos.http_util.HttpResponseResult; +import com.mgm.mcrm.common.dtos.mgm_api.PlayerProfileEntry; +import com.mgm.mcrm.common.dtos.mgm_api.UserInfoApiRecord; +import com.mgm.mcrm.common.dtos.mgm_api.WaitlistBookingApiResult; +import com.mgm.mcrm.common.dtos.mgm_api.WaitlistBookingRecord; +import com.mgm.mcrm.common.dtos.mgm_api.WaitlistDataApiResult; +import com.mgm.mcrm.common.dtos.mgm_api.WaitlistDataRecord; +import com.mgm.mcrm.logging.services.SysLogBookingService; + +@Service +public class WaitlistBookingService { + @Resource + private MGMApiService mgmApiService; + @Resource + private BookingViewDao bookViewDao; + @Resource + private BookingDao bookingDao; + @Autowired + private BookingControlMsgSender ctrlMsgSender; + @Resource + private BookingService bookingService; + @Resource + private SysLogBookingService sysLogBookingService; + @Autowired + private NonMGMBookingService nonMGMBookingService; + @Resource + private EmailDao emailDao; + @Resource + private BookingViewDao bookingViewDao; + @Resource + private GamingDataDao gamingDataDao; + @Resource + private OtherRoomStatusDao otherRoomStatusDao; + @Resource + private MgmUserService mgmUserService; + @Autowired + private OtherAllotmentDao otherAllotmentDao; + @Resource + private RoomCriteriaDao criteriaDao; + @Resource + private PlayerService playerService; + @Resource + private SettingService settingService; + @Resource + private PropertyDao propertyDao; + + @Autowired + private BookingMapper bookingMapper; + + public List getBookingsByPlayer(String playerId) throws Exception { + List bookingList = new ArrayList(); + try { + HttpResponseResult httpResult = mgmApiService.invokeWaitlistBooking(playerId); + if(httpResult.getStatusCode()==200) { + try { + WaitlistBookingApiResult resultObj = JSONObject.parseObject(httpResult.getResponseContent(),WaitlistBookingApiResult.class,Feature.SupportNonPublicField,Feature.IgnoreNotMatch); + if((resultObj!=null && resultObj.getStatusCode()!=null)) { + String resultCode = resultObj.getStatusCode(); + if(Strings.CS.equals("OK", resultCode)) { + if(resultObj.getRecords()!=null) { + List recordList = resultObj.getRecords(); + for(WaitlistBookingRecord rec:recordList) { + if(!Strings.CS.equals(rec.getBookingStatus(), "pending")) continue; + BookingsView bookingData = this.convertBookingFromRecord(rec); + if(bookingData!=null) { + bookingList.add(bookingData); + } + } + } + }else { + LogUtil.error(WaitlistBookingService.class,resultObj.getStatusDescription()); + } + }else { + LogUtil.error(WaitlistBookingService.class,"Invalid return data"); + } + }catch(Exception err) { + LogUtil.error(WaitlistBookingService.class,"Parse return data failed:"+err.getMessage()); + } + + }else { + LogUtil.error(WaitlistBookingService.class,"Invoke Waitlist Booking Failed:["+httpResult.getStatusCode()+"] "+httpResult.getErrorMessage()); + } + }catch(Exception err) { + LogUtil.error(WaitlistBookingService.class,"Invoke Waitlist Booking API error:"+err.getMessage()); + } + return bookingList; + } + + public List getWaitlistData(String bookIds) throws Exception { + List gamingList = new ArrayList(); + try { + HttpResponseResult httpResult = mgmApiService.invokeWaitlistData(bookIds, 0); + if(httpResult.getStatusCode()==200) { + try { + WaitlistDataApiResult resultObj = JSONObject.parseObject(httpResult.getResponseContent(),WaitlistDataApiResult.class,Feature.SupportNonPublicField,Feature.IgnoreNotMatch); + if((resultObj!=null && resultObj.getStatusCode()!=null)) { + String resultCode = resultObj.getStatusCode(); + if(Strings.CS.equals("OK", resultCode)) { + List recordList = resultObj.getRecords(); + for(WaitlistDataRecord rec:recordList) { + GamingData gamingData = new GamingData(); + gamingData = this.convertWaitlistDataRecord(rec); + if(gamingData.getBookId()!=null) { + gamingList.add(gamingData); + } + } + }else { + LogUtil.error(WaitlistBookingService.class,resultObj.getStatusDescription()); + } + }else { + LogUtil.error(WaitlistBookingService.class,"Invalid return data"); + } + }catch(Exception err) { + LogUtil.error(WaitlistBookingService.class,"Parse return data failed:"+err.getMessage()); + } + + }else { + LogUtil.error(WaitlistBookingService.class,"Invoke Waitlist Data Failed:["+httpResult.getStatusCode()+"] "+httpResult.getErrorMessage()); + } + }catch(Exception err) { + LogUtil.error(WaitlistBookingService.class,"Invoke Waitlist Data API error:"+err.getMessage()); + } + return gamingList; + } + + public List syncWaitlistData(String bookIds) throws Exception { + List gamingList = new ArrayList(); + gamingList = getWaitlistData(bookIds); + if(gamingList.size()>0) { + for(GamingData gd:gamingList) { + List getGaming = gamingDataDao.findByBookId(gd.getBookId()); + Date newDate = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + if(getGaming!=null&&getGaming.size()>0) { + if(getGaming.size()>1) { + gamingDataDao.deleteAll(getGaming); + gd.setCreatedAt(newDate); + gd.setUpdatedAt(newDate); + }else { + GamingData game = getGaming.getFirst(); + gd.setId(game.getId()); + gd.setCreatedAt(game.getCreatedAt()); + gd.setUpdatedAt(newDate); + } + }else { + gd.setCreatedAt(newDate); + gd.setUpdatedAt(newDate); + } + gd.setProcessStatus(0); + gamingDataDao.save(gd); + LogUtil.info(WaitlistBookingService.class,gd.getBookId()+" "+gd.getProcessStatus()); + } + } + return gamingList; + } + + public List getWaitlistBookingByPlayerId(String playerId) { + return bookViewDao.findShowWaitlisBooking(playerId); + } + + public BaseApiResponse updateWaitlistBookingStatus(Bookings booking, HttpServletRequest request) throws Exception { + BaseApiResponse processResult= new BaseApiResponse<>(); + Bookings existsType = bookingDao.findById(booking.getId()).orElse(null); + Gson gson = new Gson(); + Date creatdDate = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + if(existsType==null) { + processResult.setCode("ERR_OBJECT_NOT_FOUND"); + processResult.setMessage("Can't find Booking by Id"); + }else { + String newStatus = ""; + if(Strings.CS.equals(booking.getApproveStatus(), "W")) { + newStatus = "WA"; + existsType.setApproveStatus(newStatus); + existsType.setApprovedBy(booking.getUpdatedBy()); + existsType.setApprovedAt(creatdDate); + + if(existsType.getWaitlistId()!=null) { + if(existsType.getSegmentId()!=null) { + //extend other booking + Bookings extendBooking = bookingDao.findById(existsType.getWaitlistId()).orElse(null); + extendBooking.setRequestedCoDate(existsType.getCheckoutDate()); + extendBooking.setOtherFollowUpStatusId(Long.valueOf("3")); + extendBooking.setBookType("1"); + bookingDao.save(extendBooking); + nonMGMBookingService.processOtherAllotment(existsType.getRoomId(), existsType.getCheckoutDate(), + existsType.getCheckinDate(), existsType.getPropertyId(), existsType.getSegmentId()); + }else { + //send mgm booking email + //MGM Booking + BookingsView originBooking = bookingViewDao.findById(existsType.getWaitlistId()).orElse(null); + Bookings emailBook = existsType; + Email email = new Email(); + assert originBooking != null; + email.setBookId(originBooking.getId()); + email.setCreatedAt(creatdDate); + email.setCreatedBy(originBooking.getCreatedBy()); + +// email = SendEmail.sendExtendEmail(emailBook, originBooking,email); + if(email.getStatus()==1) { + newStatus = "WF"; + existsType.setApproveStatus(newStatus); + }else { + + } + emailDao.save(email); + } + + }else { + //create booking + Bookings newBooking = gson.fromJson(gson.toJson(existsType),Bookings.class); + newBooking.setId(null); + newBooking.setApprovedAt(null); + newBooking.setApprovedBy(null); + newBooking.setApproveStatus("PN"); + newBooking.setWaitlistId(existsType.getId()); + bookingDao.save(newBooking); + + //MGM booking sync to opera + if(newBooking.getSegmentId()==null) { + if(ctrlMsgSender!=null) { + if(SysCommon.jmsRunning) { + ctrlMsgSender.sendMessage("CREATE_OPERA_BOOKING", newBooking); + }else { + bookingService.callOWSCreateBooking(newBooking); + } + } + }else { + //扣减房间 + nonMGMBookingService.processOtherAllotment(newBooking.getRoomId(), newBooking.getCheckoutDate(), + newBooking.getCheckinDate(), newBooking.getPropertyId(), newBooking.getSegmentId()); + newStatus = "WF"; + existsType.setApproveStatus(newStatus); + } + } + + }else if(Strings.CS.equals(booking.getApproveStatus(), "WA")) { + newStatus = "WF"; + existsType.setApproveStatus(newStatus); + existsType.setApprovedBy(booking.getUpdatedBy()); + existsType.setApprovedAt( DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss")); + }else if(Strings.CS.equals(booking.getApproveStatus(), "WR")) { + newStatus = "W"; + existsType.setApproveStatus(newStatus); + existsType.setApprovedBy(null); + existsType.setApprovedAt(null); + } + + existsType.setUpdatedAt( DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss")); + existsType.setUpdatedBy(booking.getUpdatedBy()); + + bookingDao.save(existsType); + processResult.setData(existsType); + processResult.setSuccess(true); + + ArrayList booksList = new ArrayList(); + booksList.add(booking); + String oldStatus = EumnApprovalStatus.getApprovalStatusByDBValue(booking.getApproveStatus()); + String changeStatus = EumnApprovalStatus.getApprovalStatusByDBValue(newStatus); + sysLogBookingService.saveLogBooking(booksList, request,oldStatus,changeStatus, "Room Status",""); + } + return processResult; + } + + public BaseApiResponse updateBatchWaitlistBookingStatus(String[]bookIds,String status,HttpServletRequest request,boolean change) throws Exception { + BaseApiResponse processResult= new BaseApiResponse<>(); + String approvedBy = null; + Date approvedAt = null; + Long approvedId = null; + String userId = null; + String userName = null; + Gson gson = new Gson(); + boolean isApproved = false; + boolean cannotCahgne = false; + ArrayList booksList = new ArrayList(); + ArrayList newBooksList = new ArrayList(); + Date creatdDate = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + + if(request!=null) { + LoginUserInfo userInfo =SysCommon.parseUserFromToken(request); + if (userInfo != null) { + userId = userInfo.getLoginId(); + if(!StringUtils.isEmpty(userId)) { + userId = Strings.CS.replace(userId, "@mgm.mo", ""); + } + userName = userInfo.getDisplayName(); + if(userId!=null) { + try { + Long checkUserId=Long.valueOf(userId); + BaseApiResponse serviceResult = mgmUserService.findUserInfoByUserId(userId); + UserInfoApiRecord newUserInfo = serviceResult.getData(); + userName = newUserInfo.getUserName(); + } catch (Exception e) { + userName = userId; + userId = null; + } + } + } + } + + for(String v :bookIds) { + Bookings getBooking = bookingDao.findById(Long.parseLong(v)).orElse(null); + if(Strings.CS.equals(getBooking.getApproveStatus(), "WA")) { + isApproved = true; + }else if(Strings.CS.equals(getBooking.getApproveStatus(), "W")) { + + }else { + cannotCahgne = true; + } + booksList.add(getBooking); + } + if(cannotCahgne) { + processResult.setSuccess(false); + processResult.setMessage("Cannot update not pending booking"); + return processResult; + } + if(isApproved && !(Strings.CS.equals(status, "WF")||Strings.CS.equals(status, "WC"))) { + if(!change) { + processResult.setSuccess(false); + processResult.setMessage("Only can update to Reserved / Cancelled on approved booking"); + return processResult; + } + + } + + bookingDao.updateBatchStatus(status,bookIds); + if(Strings.CS.equals(status, "W")) { + bookingDao.updateBatchApprover(approvedId,approvedBy,approvedAt,bookIds); + }else if(Strings.CS.equals(status, "WA")) { + if(StringUtils.isNotEmpty(userId)) approvedId = Long.valueOf(userId); + approvedBy = userName; + approvedAt = creatdDate; + bookingDao.updateBatchApprover(approvedId,approvedBy,approvedAt,bookIds); + CfgSettings emailAddress = settingService.getSettingByKey(SysConstants.MGM_EMAIL_ADDRESS); + for (String id : bookIds) { + Bookings originBooking = bookingDao.findById(Long.parseLong(id)).orElse(null); +// BookingsView bookingView = bookingViewDao.findById(originBooking.getId()); + BookingsView bookingView = bookingViewDao.findById(Long.valueOf(id)).orElse(null); + assert bookingView != null; + bookingView = this.getEmailInfo(bookingView, bookingView.getCreatedBy()); + boolean isOverBook = this.checkIsOverbook(bookingView.getRoomId(), bookingView.getCheckinDate(), + bookingView.getCheckoutDate(), bookingView.getPropertyId(), bookingView.getBlockId()); + boolean isOtherOverBook = this.checkOtherIsOverbook(originBooking.getRoomId(), originBooking.getCheckoutDate(), + originBooking.getCheckinDate(), originBooking.getPropertyId(), originBooking.getSegmentId()); + + CfgProperties newBookingProperty = propertyDao.getById(originBooking.getPropertyId()); + if (originBooking.getWaitlistId() != null) { + if (Strings.CS.equals(newBookingProperty.getCategory(), "OTHER")) { +//send email instead of sync other booking + BookingsView originBookingView = bookingViewDao.findById(originBooking.getWaitlistId()).orElse(null); + assert originBookingView != null; + originBookingView = this.getEmailInfo(originBookingView, originBookingView.getCreatedBy()); + Bookings emailBook = originBooking; + Email email = new Email(); + + email.setBookId(originBooking.getId()); + email.setCreatedAt(creatdDate); + email.setCreatedBy(originBooking.getCreatedBy()); + + email = SendEmail.sendApprovalExtendEmail(emailBook, originBookingView, email, userId, userName, bookingView, isOtherOverBook, emailAddress.getKeyValues()); + if (email.getStatus() == 1) { + originBooking.setApproveStatus("WA"); + + bookingDao.save(originBooking); + } + emailDao.save(email); + } else { +//Send mgm booking email + BookingsView originBookingView = bookingViewDao.findById(originBooking.getWaitlistId()).orElse(null); + assert originBookingView != null; + originBookingView = this.getEmailInfo(originBookingView, originBookingView.getCreatedBy()); + Bookings emailBook = originBooking; + Email email = new Email(); + + email.setBookId(originBooking.getId()); + email.setCreatedAt(creatdDate); + email.setCreatedBy(originBooking.getCreatedBy()); + + email = SendEmail.sendApprovalExtendEmail(emailBook, originBookingView, email, userId, userName, bookingView, false, emailAddress.getKeyValues()); + if (email.getStatus() == 1) { + originBooking.setApproveStatus("WA"); + bookingDao.save(originBooking); + } else { + + } + emailDao.save(email); + } + } else { +//If overbook send email + isOverBook = false; + if ((isOverBook && originBooking.getBlockId() != null) || (isOtherOverBook && originBooking.getSegmentId() != null)) { + Bookings emailBook = originBooking; + Email email = new Email(); + + email.setBookId(originBooking.getId()); + email.setCreatedAt(creatdDate); + email.setCreatedBy(originBooking.getCreatedBy()); + + email = SendEmail.sendApprovalNewEmail(emailBook, bookingView, email, userId, userName, true, false, emailAddress.getKeyValues()); + if (email.getStatus() == 1) { + originBooking.setApproveStatus("WA"); + bookingDao.save(originBooking); + } + emailDao.save(email); + } else { + Bookings newBooking = gson.fromJson(gson.toJson(originBooking), Bookings.class); + newBooking.setId(null); + newBooking.setApprovedAt(creatdDate); + newBooking.setCreatedAt(creatdDate); + newBooking.setApprovedBy(userName); +// newBooking.setOtherRoomStatusId(otherRoomStatusDao.getPendingId()); + newBooking.setApproveStatus("PN"); + newBooking.setWaitlistId(originBooking.getId()); + newBooking.setSectionId(originBooking.getSectionId()); + + if (userId != null) { + try { + newBooking.setApprovedId(Long.valueOf(userId)); + } catch (Exception e) { + } + } + + + bookingDao.save(newBooking); + newBooksList.add(newBooking); + + +//MGM booking sync to opera + if (Strings.CS.equals(newBookingProperty.getCategory(), "OPERA")) { + if (ctrlMsgSender != null) { + if (SysCommon.jmsRunning) { + ctrlMsgSender.sendMessage("CREATE_OPERA_BOOKING", newBooking); + } else { + bookingService.callOWSCreateBooking(newBooking); + } + } + } else if (Strings.CS.equals(newBookingProperty.getCategory(), "DAYLIGHT")) { + ctrlMsgSender.sendMessage("CREATE_DAYLIGHT_BOOKING", newBooking); + } else { +//扣减房间 + nonMGMBookingService.processOtherAllotment(originBooking.getRoomId(), originBooking.getCheckoutDate(), + originBooking.getCheckinDate(), originBooking.getPropertyId(), originBooking.getSegmentId()); + originBooking.setApproveStatus("WF"); + bookingDao.save(originBooking); + } + } + if ((Strings.CS.equals(originBooking.getRoomTypeCode(), "R2")) || + Strings.CS.equals(originBooking.getRoomTypeCode(), "Y2")) { + Bookings emailBook = originBooking; + Email email = new Email(); + + email.setBookId(originBooking.getId()); + email.setCreatedAt(creatdDate); + email.setCreatedBy(originBooking.getCreatedBy()); + + email = SendEmail.sendApprovalNewEmail(emailBook, bookingView, email, userId, userName, false, true, emailAddress.getKeyValues()); + emailDao.save(email); + } + + } + + } + + }else if(Strings.CS.equals(status, "WR")||Strings.CS.equals(status, "WF")) { + if(StringUtils.isNotEmpty(userId)) approvedId = Long.valueOf(userId); + approvedBy = userName; + approvedAt = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + bookingDao.updateBatchApprover(approvedId,approvedBy,approvedAt,bookIds); + } + String changeStatus = EumnApprovalStatus.getApprovalStatusByDBValue(status); + sysLogBookingService.saveLogBooking(booksList, request,"",changeStatus, "Waitlist Status","approve_status"); + sysLogBookingService.saveLogBooking(newBooksList, request, "", "", "Create Booking(Sync from Waitlist)",""); + + processResult.setData(bookIds); + processResult.setSuccess(true); + return processResult; + } + + + private BookingsView convertBookingFromRecord(WaitlistBookingRecord rec) { + BookingsView booking = null; + if(rec!=null) { + if(StringUtils.isNotBlank(rec.getBookingId())) { + BookingsView matchBooking = bookViewDao.findById(Long.valueOf(rec.getBookingId())).orElse(null); + if(matchBooking!=null) { + if(matchBooking.getCheckoutDate().getTime()>DateTimeUtil.getCurrentDateTime("yyyy-MM-dd").getTime()) { + booking = matchBooking; + } + } + } + } + return booking; + } + + //检查other booking是否overbook + public boolean checkOtherIsOverbook(Long roomId,Date checkoutDate,Date checkinDate,Long propertyId,Long segmentId) { + boolean isOverbook = false; + List roomIds = new ArrayList(); + roomIds.add(Long.valueOf(String.valueOf(roomId))); + Date endDate = DateTimeUtil.addDay(checkoutDate, -1); + List criterias = otherAllotmentDao.findByRoomIdInAndPropertyIdAndBookDateBetween + (roomIds,propertyId,checkinDate,endDate); + if(criterias.size()==0) isOverbook = true; + Long[] roomStatusId = otherRoomStatusDao.findIsPickUpId(); + for(CfgOtherAllotment c:criterias) { + CfgOtherAppChannel channel = new CfgOtherAppChannel(); + Set channels = c.getChannels(); + if(channels.size()==0) isOverbook = true; + for(CfgOtherAppChannel a:channels) { + if(a.getSegmentId()!=null&&segmentId!=null) { + if(a.getSegmentId().longValue()==segmentId.longValue()) { + channel = a; + int pickUp = 0; + Integer appChannel = 0; + pickUp = bookingDao.getOtherPickupBooking(propertyId, roomId, segmentId, c.getBookDate(), roomStatusId); + pickUp = pickUp+1; + if(channel.getAppChannel()!=null) { + appChannel = channel.getAppChannel(); + } + if(appChannel-pickUp<0) { + isOverbook = true; + break; + } + } + } + } + } + return isOverbook; + } + + //检查other booking是否overbook + public boolean checkIsOverbook(Long roomId,Date checkinDate ,Date checkoutDate,Long propertyId,Long blockId) { + boolean isOverbook = false; + List roomIds = new ArrayList(); + roomIds.add(roomId); + Date endDate = DateTimeUtil.addDay(checkoutDate, -1); + List criterias = criteriaDao.findByRoomIdInAndPropertyIdAndBookDateBetween + (roomIds,propertyId,checkinDate,endDate); + if(criterias.size()==0) isOverbook = true; + for(CfgRoomCriterias c:criterias) { + CfgAppChannel channel = new CfgAppChannel(); + Set channels = c.getChannels(); + if(channels.size()==0) isOverbook = true; + for(CfgAppChannel a:channels) { + if(a.getBlockId()!=null&&blockId!=null) { + if(a.getBlockId().longValue()==blockId.longValue()) { + channel = a; + int pickUp = 0; + Integer appChannel = 0; + pickUp = bookingDao.getPickupBooking(propertyId, roomId, blockId, c.getBookDate()); + pickUp = pickUp+1; + if(channel.getAppChannel()!=null) { + appChannel = channel.getAppChannel(); + } + if(appChannel-pickUp<0) { + isOverbook = true; + break; + } + } + } + + } + } + return isOverbook; + } + + private GamingData convertWaitlistDataRecord(WaitlistDataRecord rec) { + GamingData gaming = new GamingData(); + if(rec!=null) { + gaming.setBookId(Long.valueOf(rec.getBookingId())); + gaming.setOverlapBooking(rec.getOverlapBooking()); + gaming.setMaBooking(rec.getmABooking()); + gaming.setR3ActualWin(rec.getR3ActualWin()); + gaming.setR3TheoWin(rec.getR3TheoWin()); + gaming.setR3Tpd(rec.getR3TPD()); + gaming.setR6ActualWin(rec.getR6ActualWin()); + gaming.setR6TheoWin(rec.getR6TheoWin()); + gaming.setR6Tpd(rec.getR6TPD()); + gaming.setR12ActualWin(rec.getR12ActualWin()); + gaming.setR12TheoWin(rec.getR12TheoWin()); + gaming.setR12Tpd(rec.getR12TPD()); + gaming.setFinalSegment(rec.getFinalSegment()); + gaming.setTripTheoProfit(rec.getTripTheoProfit()); + gaming.setDailyTheoProfit(rec.getDailyTheoProfit()); + gaming.setPlayerType(rec.getPlayerType()); + gaming.setRankingByPlayer(rec.getRankingByPlayer()); + gaming.setBookerTeam(rec.getBookerTeam()); + gaming.setCurrentTripTheoWinAmount(rec.getCurrentTripTheoWinAmount()); + gaming.setLast2dayTheoWinAmount(rec.getLast2DayTheoWinAmount()); + } + return gaming; + } + + private BookingsView getEmailInfo(BookingsView bookView,String userId) { + if(bookView!=null) { + JSONArray dynList = !StringUtils.isEmpty(bookView.getSharer())&&!Strings.CS.equals("[]", bookView.getSharer())? + JSONArray.parseArray(bookView.getSharer()) :new JSONArray(); + String sharerString = ""; + if (dynList.size()>0) { + for (int a = 0; a < dynList.size(); a++) { + Gson gson = new Gson(); + JSONObject shareObj = (JSONObject) dynList.get(a); + String sharePlayerId = shareObj.getString("playerId"); + String shareName = shareObj.getString("name"); + LogUtil.info(BookingService.class, + "[editBooking] sharePlayerId " + gson.toJson(sharePlayerId)); + LogUtil.info(BookingService.class, + "[editBooking] shareName " + gson.toJson(shareName)); + if(!StringUtils.isEmpty(sharePlayerId)) { + sharerString+=(sharePlayerId+" "+shareName)+" "; + }else if(!StringUtils.isEmpty(shareName)) { + sharerString+=(shareName)+" "; + }else { + continue; + } + } + } + bookView.setSharerName(sharerString); + String playerId = bookView.getPlayerId()!=null? bookView.getPlayerId():null; + BaseApiResponse res = playerService.findWebPlayerProfileByPlayerId(playerId); + if(res.isSuccess()) { + try { + PlayerProfileEntry profile = res.getData(); + bookView.setMemberTier(profile.getTierName()); + bookView.setMemberLastName(profile.getName()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + } + return bookView; + } + + public List getExpiryWaitlistBooking() { + List expiryBooking = bookingDao.getExpiryWaitlistBooking(); + return expiryBooking; + } + + public int expiryWaitlistBooking(Bookings booking) { + int res = bookingDao.expiryWaitlistBooking(booking.getId().longValue()); + return res; + } + + public List getPendingWaitlistBooking() { + List waitlistBooking = bookingDao.getPendingWaitlistBooking(); + return waitlistBooking; + } + + public List findGamingDataByBookId(long id) { + List getGaming = gamingDataDao.findByBookId(id); + return getGaming; + } + + public List getWaitlistBookingByPlayerId_Optimize(String playerId) { + return bookingMapper.viewToBookingDtoList(bookViewDao.findShowWaitlisBooking(playerId)); + } + +} + diff --git a/src/main/java/com/mgm/mcrm/booking/services/mockup/BookingServiceMockup.java b/src/main/java/com/mgm/mcrm/booking/services/mockup/BookingServiceMockup.java new file mode 100644 index 0000000..815d9be --- /dev/null +++ b/src/main/java/com/mgm/mcrm/booking/services/mockup/BookingServiceMockup.java @@ -0,0 +1,185 @@ +package com.mgm.mcrm.booking.services.mockup; + +import com.alibaba.fastjson.JSONObject; +import com.mgm.mcrm.appsetting.services.SysSettingService; +import com.mgm.mcrm.authorization.services.MgmUserService; +import com.mgm.mcrm.basesetting.room.models.CfgRoomFeatures; +import com.mgm.mcrm.basesetting.room.repositories.RoomFeatureDao; +import com.mgm.mcrm.booking.dtos.BookingDto; +import com.mgm.mcrm.booking.mappers.BookingMapper; +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.booking.models.BookingsView; +import com.mgm.mcrm.booking.repositories.BookingDao; +import com.mgm.mcrm.booking.repositories.BookingViewDao; +import com.mgm.mcrm.booking.services.OperaDBBookingService; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.common.dtos.mgm_api.UserInfoApiRecord; +import com.mgm.mcrm.common.utils.DateTimeUtil; +import jakarta.annotation.Resource; +import jakarta.transaction.Transactional; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +@Slf4j +@Service +public class BookingServiceMockup { + + @Resource + private BookingViewDao bookingViewDao; + @Resource + private BookingMapper bookingMapper; + @Resource + private RoomFeatureDao roomFeatureDao; + @Resource + private SysSettingService sysSettingService; + @Resource + private BookingDao bookingDao; + @Resource + private OperaDBBookingService operaDBService; + @Resource + private MgmUserService mgmUserService; + + public List getSearchRecordMock(String checkinDate, + String checkoutDate, String playerId) { + return bookingViewDao.findRecordSearchMock(playerId, checkinDate,checkoutDate); + } + + @Transactional + public List getSearchRecordMock_Optimize(String checkinDate, + String checkoutDate, + String playerId) { + List bookingsViews = bookingViewDao.findRecordSearchMock(playerId, checkinDate,checkoutDate); + List bookingDtos = bookingMapper.viewToBookingDtoList(bookingsViews); + Date currentTime = new Date(); + for(BookingDto booking:bookingDtos){ + booking.setDataTime(currentTime); + } + return bookingDtos; + } + + public List getBookingByConfirmationNoMock(String conf) { + + List list = bookingViewDao.findBookingByConfirmationNo(conf); + + if (list != null && !list.isEmpty()) { + for (BookingsView booking : list) { + if ("FC".equals(booking.getApproveStatus()) && booking.getConfirmationNo() != null) { + booking.setApproveStatus("N"); + } + // build special request + if (booking.getFeatureCode() != null && !booking.getFeatureCode().isEmpty()) { + String[] arrSpecialCode = booking.getFeatureCode().split(","); + String specialStr = ""; + if (arrSpecialCode.length > 0) { + for (int j = 0; j < arrSpecialCode.length; j++) { + if (!arrSpecialCode[j].isEmpty()) { + CfgRoomFeatures features = roomFeatureDao.getByOperaCode(arrSpecialCode[j]); + if (features != null) { + if (specialStr.isEmpty()) { + specialStr = features.getDescription(); + } else { + specialStr = specialStr + ", " + features.getDescription(); + } + } + } + } + booking.setSpecialName(specialStr); + } + } + //build sharer + String expDate = StringUtils.upperCase("FORM"); + String profileExpDate = StringUtils.upperCase("form"); + if (StringUtils.isEmpty(profileExpDate)) { + expDate = profileExpDate; + } else if (Strings.CS.contains(profileExpDate, "FORM")) { + + } else { + if (!StringUtils.isEmpty(expDate) && !Strings.CS.contains(expDate, "FORM")) { + Date edateTime = DateTimeUtil.getDateFromString(expDate, "yyyy-MM-dd"); + Date proShareEdateTime = DateTimeUtil.getDateFromString(profileExpDate, "yyyy-MM-dd"); + if (proShareEdateTime.getTime() < edateTime.getTime()) expDate = profileExpDate; + } else if (Strings.CS.contains(expDate, "FORM")) { + expDate = profileExpDate; + } + + } + booking.setExpDate(expDate); + + //if booker Name & booker Team is null + if (booking.getBookerTeam() == null && booking.getBooker() == null){ + if(!StringUtils.isEmpty(booking.getCreatedBy())) { + BaseApiResponse userInfoRes = mgmUserService.findUserInfoByUserId(booking.getCreatedBy()); + if(userInfoRes.isSuccess()) { + UserInfoApiRecord userInfo = userInfoRes.getData(); + booking.setBooker(userInfo.getUserName()); + booking.setCreatedByName(userInfo.getUserName()); + } + } + } + + boolean isOperaShare = this.checkRoomNo(booking.getId(), + DateTimeUtil.getDateByFormat(booking.getCheckinDate(), "yyyy-MM-dd"), + DateTimeUtil.getDateByFormat(booking.getCheckoutDate(), "yyyy-MM-dd")); + booking.setShare(!isOperaShare); + + ArrayList dates = new ArrayList<>(); + ArrayList dateList = new ArrayList<>(); + JSONObject obj = new JSONObject(); + int numOfNight = Integer.parseInt(DateTimeUtil.getDiffDate(booking.getCheckinDate(), booking.getCheckoutDate(), "day")); + booking.setNumOfNight(numOfNight); + // build datelist + for (int j = 0; j < numOfNight + 1; j++) { + dates.add(DateTimeUtil.getDateByFormat(DateTimeUtil.addDay(booking.getCheckinDate(), j), "yyyy-MM-dd")); + } + obj.put("date", dates); + obj.put("numOfNight", booking.getNumOfNight()); + obj.put("numOfRoom", 1); + obj.put("checked", true); + dateList.add(obj); + booking.setDateList(dateList); + booking.setShare(false); + } + } + return list; + } + + public boolean checkRoomNo(Long id,String checkinDate, String checkoutDate) { + boolean isMock = sysSettingService.isMockReplicate(); + if(isMock) return true; + Bookings book = bookingDao.findById(id).orElse(null); + List results = new ArrayList(); + List roomList = new ArrayList(); + long startDate = DateTimeUtil.getLongFromDate(DateTimeUtil.getDateFromString(checkinDate,"yyyy-MM-dd")); + long endDate = DateTimeUtil.getLongFromDate(DateTimeUtil.getDateFromString(checkoutDate,"yyyy-MM-dd")); + results = operaDBService.getBookingsByConfirmationNo(book.getConfirmationNo()); + + if(!results.isEmpty()) { + roomList = operaDBService.getBookingsByRoomNo(results.getFirst().getRoomNo()); + }else { + return false; + } + if(!roomList.isEmpty()) { + for(int i = 0;i=roomStartDate&&startDateroomStartDate&&endDate<=roomEndDate) || + (startDateroomEndDate) ) return false; + } + } + } + return true; + }else { + return true; + } + } +} + diff --git a/src/main/java/com/mgm/mcrm/common/annotation/logging/OperationLog.java b/src/main/java/com/mgm/mcrm/common/annotation/logging/OperationLog.java new file mode 100644 index 0000000..db1809f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/annotation/logging/OperationLog.java @@ -0,0 +1,13 @@ +package com.mgm.mcrm.common.annotation.logging; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface OperationLog { + public String eventCode(); + public String actionName(); +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/common/annotation/security/AccessToken.java b/src/main/java/com/mgm/mcrm/common/annotation/security/AccessToken.java new file mode 100644 index 0000000..5aa8923 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/annotation/security/AccessToken.java @@ -0,0 +1,11 @@ +package com.mgm.mcrm.common.annotation.security; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface AccessToken { +} diff --git a/src/main/java/com/mgm/mcrm/common/annotation/security/PassToken.java b/src/main/java/com/mgm/mcrm/common/annotation/security/PassToken.java new file mode 100644 index 0000000..3fb4b73 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/annotation/security/PassToken.java @@ -0,0 +1,11 @@ +package com.mgm.mcrm.common.annotation.security; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface PassToken { +} diff --git a/src/main/java/com/mgm/mcrm/common/config/DataSourceConfig.java b/src/main/java/com/mgm/mcrm/common/config/DataSourceConfig.java new file mode 100644 index 0000000..0077631 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/config/DataSourceConfig.java @@ -0,0 +1,32 @@ +package com.mgm.mcrm.common.config; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +/** + * @Description: 数据源配置 + */ +@Configuration +public class DataSourceConfig { + + @Bean(name = "mgmDataSource") + @Qualifier("mgmDataSource") + @ConfigurationProperties(prefix = "spring.datasource.mgm") + @Primary + public DataSource mgmDataSource() { + return DataSourceBuilder.create().build(); + } + + @Bean(name = "operaDataSource") + @Qualifier("operaDataSource") + @ConfigurationProperties(prefix = "spring.datasource.opera") + public DataSource operaDataSource() { + return DataSourceBuilder.create().build(); + } +} diff --git a/src/main/java/com/mgm/mcrm/common/config/HttpClientConfig.java b/src/main/java/com/mgm/mcrm/common/config/HttpClientConfig.java new file mode 100644 index 0000000..76a54ba --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/config/HttpClientConfig.java @@ -0,0 +1,118 @@ +package com.mgm.mcrm.common.config; + +import com.mgm.mcrm.common.httpclient.HttpSslSupport; +import jakarta.annotation.PreDestroy; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.client5.http.socket.ConnectionSocketFactory; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.core5.http.config.Registry; +import org.apache.hc.core5.http.config.RegistryBuilder; +import org.apache.hc.core5.util.Timeout; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * HttpClient 配置类 + * + * 提供统一的 HttpClient Bean 配置,包括: + * - SSL 配置 + * - 连接池配置 + * - 请求超时配置 + * + * 配置参数从 application.yml 中读取: + * - httpclient.pool.max-total: 连接池最大连接数,默认 100 + * - httpclient.pool.max-per-route: 每个路由最大连接数,默认 10 + * - httpclient.timeout.connection-request: 连接请求超时时间(秒),默认 5 + * - httpclient.timeout.response: 响应超时时间(秒),默认 10 + * - httpclient.redirects-enabled: 是否启用重定向,默认 false + * + * @author Aaka + */ +@Configuration +public class HttpClientConfig { + + @Value("${httpclient.pool.max-total:100}") + private int maxTotal; + + @Value("${httpclient.pool.max-per-route:30}") + private int maxPerRoute; + + @Value("${httpclient.timeout.connection-request:10}") + private int connectionRequestTimeout; + + @Value("${httpclient.timeout.response:10}") + private int responseTimeout; + + @Value("${httpclient.redirects-enabled:false}") + private boolean redirectsEnabled; + + private PoolingHttpClientConnectionManager connectionManager; + + /** + * 创建带 SSL 配置的 HttpClient Bean + * + * @return 配置好的 CloseableHttpClient 实例 + */ + @Bean(name = "httpClientWithSSL") + public CloseableHttpClient httpClientWithSSL() { + // 使用 SSLs 配置 SSL + HttpSslSupport ssls = HttpSslSupport.getInstance(); + @SuppressWarnings("deprecation") + SSLConnectionSocketFactory sslConnFactory = ssls.getSSLCONNSF(HttpSslSupport.SSLProtocolVersion.TLSv1_2); + + // 注意:ConnectionSocketFactory 和 SSLConnectionSocketFactory 在 HttpClient 5 中被标记为 deprecated, + // 但这是目前唯一可用的方式,新的 API 尚未稳定 + @SuppressWarnings("deprecation") + Registry registry = RegistryBuilder.create() + .register("https", sslConnFactory) + .build(); + + // 注意:PoolingHttpClientConnectionManager 构造函数在 HttpClient 5 中被标记为 deprecated, + // 但这是目前唯一可用的方式 + @SuppressWarnings("deprecation") + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(registry); + connManager.setMaxTotal(maxTotal); + connManager.setDefaultMaxPerRoute(maxPerRoute); + + this.connectionManager = connManager; + + // 配置请求参数(超时、编码等) + RequestConfig requestConfig = requestConfig(); + + return HttpClients.custom() + .setConnectionManager(connManager) + .setDefaultRequestConfig(requestConfig) + .setConnectionManagerShared(false) + .build(); + } + + /** + * 创建 RequestConfig Bean + * + * @return 配置好的 RequestConfig 实例 + */ + @Bean(name = "httpRequestConfig") + public RequestConfig requestConfig() { + return RequestConfig.custom() + .setConnectionRequestTimeout(Timeout.ofSeconds(connectionRequestTimeout)) + .setResponseTimeout(Timeout.ofSeconds(responseTimeout)) + .setRedirectsEnabled(redirectsEnabled) + .build(); + } + + /** + * 关闭连接管理器 + * 在 Spring Bean 销毁时自动调用 + */ + @PreDestroy + public void close() { + if (connectionManager != null) { + connectionManager.close(); + } + } +} + diff --git a/src/main/java/com/mgm/mcrm/common/config/HttpHeader.java b/src/main/java/com/mgm/mcrm/common/config/HttpHeader.java new file mode 100644 index 0000000..f64ce85 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/config/HttpHeader.java @@ -0,0 +1,26 @@ +package com.mgm.mcrm.common.config; + +import lombok.Data; + +/** + * HTTP 請求頭配置類 + * 用於自定義 HTTP 請求頭的值 + * + * @author System + */ +@Data +public class HttpHeader { + public static final String ACCEPT = "Accept"; + public static final String ACCEPT_CHARSET = "Accept-Charset"; + public static final String ACCEPT_ENCODING = "Accept-Encoding"; + public static final String ACCEPT_LANGUAGE = "Accept-Language"; + public static final String ACCEPT_RANGES = "Accept-Ranges"; + public static final String AUTHORIZATION = "Authorization"; + public static final String CACHE_CONTROL = "Cache-Control"; + public static final String CONNECTION = "Connection"; + public static final String COOKIE = "Cookie"; + public static final String CONTENT_LENGTH = "Content-Length"; + public static final String CONTENT_TYPE = "Content-Type"; + public static final String USER_AGENT = "user-agent"; +} + diff --git a/src/main/java/com/mgm/mcrm/common/config/JMSConfig.java b/src/main/java/com/mgm/mcrm/common/config/JMSConfig.java new file mode 100644 index 0000000..53bbc44 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/config/JMSConfig.java @@ -0,0 +1,74 @@ +package com.mgm.mcrm.common.config; + +import java.net.ConnectException; + +import jakarta.jms.ConnectionFactory; +import jakarta.jms.ExceptionListener; +import jakarta.jms.JMSException; + +import org.apache.activemq.ActiveMQConnectionFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jms.config.DefaultJmsListenerContainerFactory; + +import com.mgm.mcrm.common.constants.SysCommon; + +@Configuration +public class JMSConfig { + + @Value("${spring.activemq.broker-url}") + private String activeMQServer; + @Value("${spring.activemq.user}") + private String userName; + @Value("${spring.activemq.password}") + private String password; + @Value("${spring.activemq.concurrency}") + private String concurrencyCfg="3-10"; + + @Bean + public ConnectionFactory connectionFactory(){ + ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(); + connectionFactory.setBrokerURL(activeMQServer); + connectionFactory.setUserName(userName); + connectionFactory.setPassword(password); + return connectionFactory; + + } + + @Bean(name = "jmsQueueListenerCF") + public DefaultJmsListenerContainerFactory jmsQueueListenerContainerFactory() { + DefaultJmsListenerContainerFactory factory = + new DefaultJmsListenerContainerFactory(); + factory.setConnectionFactory(connectionFactory()); + factory.setConcurrency(concurrencyCfg); + factory.setPubSubDomain(false); + factory.setRecoveryInterval(20000L); + factory.setExceptionListener(new JMSErrorHandler()); + factory.setSessionAcknowledgeMode(jakarta.jms.Session.CLIENT_ACKNOWLEDGE); + factory.setAutoStartup(true); + return factory; + } + @Bean(name = "jmsTopicListenerCF") + public DefaultJmsListenerContainerFactory jmsTopicListenerContainerFactory() { + DefaultJmsListenerContainerFactory factory = + new DefaultJmsListenerContainerFactory(); + factory.setConnectionFactory(connectionFactory()); + factory.setConcurrency("1"); + factory.setPubSubDomain(true); + factory.setRecoveryInterval(20000L); + factory.setExceptionListener(new JMSErrorHandler()); + factory.setSessionAcknowledgeMode(jakarta.jms.Session.CLIENT_ACKNOWLEDGE); + factory.setAutoStartup(true); + return factory; + } + + private class JMSErrorHandler implements ExceptionListener { + @Override + public void onException(JMSException exception) { + if(exception.getCause()!=null && exception.getCause() instanceof ConnectException) { + SysCommon.jmsRunning=false; + } + } + } +} diff --git a/src/main/java/com/mgm/mcrm/common/config/MGMDataSourceConfig.java b/src/main/java/com/mgm/mcrm/common/config/MGMDataSourceConfig.java new file mode 100644 index 0000000..c3f13fb --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/config/MGMDataSourceConfig.java @@ -0,0 +1,74 @@ +package com.mgm.mcrm.common.config; + +import java.util.Map; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings; +import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * @Description: 主数据源配置 + * @date + */ +@Configuration +@EnableTransactionManagement +@EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactory", + transactionManagerRef = "transactionManager", + basePackages = {"com.mgm.mcrm"}) +public class MGMDataSourceConfig { + + @Autowired + @Qualifier("mgmDataSource") + private DataSource mrbsDataSource; + + @Primary + @Bean(name = "mgmJpaProperties") + @ConfigurationProperties(prefix = "spring.jpa.mgm") + public JpaProperties jpaProperties() { + return new JpaProperties(); + } + + @Primary + @Bean(name = "entityManager") + public EntityManager entityManager( @Qualifier("entityManagerFactory") EntityManagerFactory factory) { + return factory.createEntityManager(); + } + + @Primary + @Bean(name = "entityManagerFactory") //mrbs实体工厂 + public LocalContainerEntityManagerFactoryBean entityManagerFactory (@Qualifier("mgmDataSource") DataSource mgmDataSource, + @Qualifier("mgmJpaProperties") JpaProperties jpaProperties,EntityManagerFactoryBuilder builder) { + return builder.dataSource(mgmDataSource) + .properties(jpaProperties.getProperties()) + .properties( + new HibernateProperties() + .determineHibernateProperties( + jpaProperties.getProperties(), new HibernateSettings())) + .packages("com.mgm.mcrm") //实体类所在位置 + .persistenceUnit("mgmPersistenceUnit") + .build(); + } + + @Primary + @Bean(name = "transactionManager") + public PlatformTransactionManager transactionManager(@Qualifier("entityManagerFactory") EntityManagerFactory factory) { + return new JpaTransactionManager(factory); + } + +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/common/config/OperaDataSourceConfig.java b/src/main/java/com/mgm/mcrm/common/config/OperaDataSourceConfig.java new file mode 100644 index 0000000..7b826b9 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/config/OperaDataSourceConfig.java @@ -0,0 +1,69 @@ +package com.mgm.mcrm.common.config; + +import java.util.Map; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings; +import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * @Description: 副数据源配置 + * @date + */ +@Configuration +@EnableTransactionManagement +@EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactoryOpera", + transactionManagerRef = "transactionManagerOpera") +public class OperaDataSourceConfig { + + @Autowired + @Qualifier("operaDataSource") + private DataSource operaDataSource; + + @Bean(name = "operaJpaProperties") + @ConfigurationProperties(prefix = "spring.jpa.opera") + public JpaProperties jpaProperties() { + return new JpaProperties(); + } + + @Bean(name = "entityManagerOpera") + public EntityManager entityManager( @Qualifier("entityManagerFactoryOpera") EntityManagerFactory factory) { + return factory.createEntityManager(); + } + + @Bean(name = "entityManagerFactoryOpera") + public LocalContainerEntityManagerFactoryBean entityManagerFactoryOpera (@Qualifier("operaDataSource") DataSource operaDataSource, + @Qualifier("operaJpaProperties") JpaProperties jpaProperties,EntityManagerFactoryBuilder builder) { + return builder.dataSource(operaDataSource) + .properties(jpaProperties.getProperties()) + .properties( + new HibernateProperties() + .determineHibernateProperties( + jpaProperties.getProperties(), new HibernateSettings())) + .packages("com.mgm.mcrm.booking.models") //实体类所在位置 + .persistenceUnit("operaPersistenceUnit") + .build(); + } + + @Bean(name = "transactionManagerOpera") + public PlatformTransactionManager transactionManagerOpera(@Qualifier("entityManagerFactoryOpera") EntityManagerFactory factory) { + return new JpaTransactionManager(factory); + } + +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/common/config/SwaggerConfig.java b/src/main/java/com/mgm/mcrm/common/config/SwaggerConfig.java new file mode 100644 index 0000000..32fcd67 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/config/SwaggerConfig.java @@ -0,0 +1,18 @@ +package com.mgm.mcrm.common.config; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SwaggerConfig { + @Bean + public OpenAPI customOpenAPI() { + return new OpenAPI() + .info(new Info() + .title("API Document for MGM Daylight application") + .version("1.0") + .description("API document for MGM Daylight application")); + } +} diff --git a/src/main/java/com/mgm/mcrm/common/config/WebFilterConfig.java b/src/main/java/com/mgm/mcrm/common/config/WebFilterConfig.java new file mode 100644 index 0000000..6458ad7 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/config/WebFilterConfig.java @@ -0,0 +1,88 @@ +package com.mgm.mcrm.common.config; + +import com.mgm.mcrm.appsetting.services.SettingService; +import com.mgm.mcrm.authorization.filters.JwtAuthFilter; +import com.mgm.mcrm.authorization.services.UserTokenService; +import com.mgm.mcrm.authorization.utils.JwtTokenUtil; +import com.mgm.mcrm.common.filters.ConfigHeaderFilter; +import jakarta.annotation.Resource; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; + +import java.util.Arrays; +import java.util.List; + +@Configuration +public class WebFilterConfig { + + @Resource + private UserTokenService userTokenService; + + @Resource + private SettingService settingService; + + @Value("${mcrm.security.jwt.secret-key}") + private String secretKey; + + @Value("${mcrm.security.jwt.api-token-expiration}") + private int apiTokenExpiration; + + @Value("${mcrm.security.jwt.mobile-session-expiration}") + private int mobileSessionExpiration; + + @Bean + public TaskScheduler taskScheduler() { + ThreadPoolTaskScheduler scheduling = new ThreadPoolTaskScheduler(); + scheduling.setPoolSize(10); + scheduling.initialize(); + return scheduling; + } + + @Bean + public FilterRegistrationBean registerHeaderFilter() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(new ConfigHeaderFilter()); + registration.addUrlPatterns("/*"); + registration.setName("ConfigHeaderFilter"); + registration.setOrder(Ordered.HIGHEST_PRECEDENCE); + return registration; + } + + @Bean + public FilterRegistrationBean jwtAuthFilter() { + JwtTokenUtil.setSecretKey(secretKey); + JwtTokenUtil.setAppSessionExpiration(apiTokenExpiration); + JwtTokenUtil.setAppSessionExpiration(mobileSessionExpiration); + List excludePatterns = Arrays.asList( + "/api/system/write_log", + "/api/system/sys_setting/get_list", + "/api/app/sso/*", + "/api/app/booking/mock_cancel", + "/api/web/setting/get_setting_by_key", + "/swagger*/*", + "/v3/**", + "/api-docs", + "/api-docs/**", + "/webjars/**", + "/swagger-resources/**" + ); + + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + JwtAuthFilter filter = new JwtAuthFilter(); + filter.setUserTokenService(userTokenService); + filter.setExcludePatterns(excludePatterns); + filter.setSettingService(settingService); + registrationBean.setFilter(filter); + registrationBean.addUrlPatterns("/*"); + registrationBean.setOrder(2); + registrationBean.setName("RequestJwtFilter"); + + return registrationBean; + } + +} diff --git a/src/main/java/com/mgm/mcrm/common/constants/SysCommon.java b/src/main/java/com/mgm/mcrm/common/constants/SysCommon.java new file mode 100644 index 0000000..3f304a1 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/constants/SysCommon.java @@ -0,0 +1,690 @@ +package com.mgm.mcrm.common.constants; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Field; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; + +import com.mgm.mcrm.authorization.dtos.LoginUserInfo; +import com.mgm.mcrm.authorization.models.SysUser; +import com.mgm.mcrm.authorization.models.SysUserView; +import jakarta.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.springframework.boot.system.ApplicationHome; +import org.springframework.context.MessageSource; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.web.servlet.support.RequestContextUtils; + +import com.alibaba.fastjson.JSONObject; +import com.auth0.jwt.JWT; +import com.auth0.jwt.interfaces.DecodedJWT; + +import com.mgm.mcrm.logging.models.SysLogLogin; +import com.mgm.mcrm.logging.models.SysLogOperation; +import com.mgm.mcrm.appsetting.models.SysSetting; +import com.mgm.mcrm.common.dtos.config.APIConfig; +import com.mgm.mcrm.common.dtos.msg.AppSettingMsgData; +import com.mgm.mcrm.common.dtos.msg.UpdateCfgItem; +import com.mgm.mcrm.common.dtos.system.AppServerState; +import com.mgm.mcrm.booking.services.BookingService; +import com.mgm.mcrm.common.utils.LogUtil; +import com.mgm.mcrm.common.utils.NetworkUtil; + +public class SysCommon { + + public static String runtime_path = ""; + public static String serverIp=""; + public static String serverName=""; + public static boolean dbDebugLog = false; + public static boolean apiDebugLog = false; + public static boolean appDebugLog = false; + public static boolean mgmApiMockup =true; + public static boolean jmsRunning=false; + 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; + public static String tokenSecret = "SecretKeyWhichShouldBeLongEnoughToBeSecure67848563"; + public static APIConfig apiConfig = new APIConfig(); + private static Map notifyTemplateMap = new HashMap(); + private static Map appServerStates = new HashMap(); + private static List allowOriginSource = new ArrayList(); + private static List soapServers = new ArrayList(); + private static List httpApiServers = new ArrayList(); + private static List allowIPSource = new ArrayList(); + // @Autowired + private static MessageSource messageSource; + + public static String getSystemPath() { + ApplicationHome h = new ApplicationHome(SysCommon.class); + File f = h.getSource(); + return f.getParentFile().toString(); + } + + public static void initRuntimePath() { + runtime_path = getSystemPath(); + } + + public static boolean loadSystemConfig() { + boolean isLoaded = true; + Properties props = new Properties(); + try { + initRuntimePath(); + // load config from appconfig.properties + String configFile = runtime_path + "/crm_mobile_runtime/appconfig.properties"; + InputStream inStream = new BufferedInputStream(new FileInputStream(configFile)); + props.load(inStream); + //--Server Info + serverIp = NetworkUtil.getInternalIp(); + serverName = NetworkUtil.getServerName(); + loadAPIConfig(props); + } catch (Exception e) { + isLoaded = false; + LogUtil.error(SysCommon.class, "Load configuration error:" + e.getMessage()); + } finally { + props.clear(); + props = null; + } + return isLoaded; + } + + public static void loadSettingsFromDB(List sysSettings) { + System.out.println("[SysCommon][loadSettingsFromDB] Load settings from DB, setting size=" + sysSettings.size()); + for(int i=0; i0) { + contentBuffer.append("\n"); + } + contentBuffer.append(lineData); + lineCnt++; + } + bufferedReader.close(); + fileContent = contentBuffer.toString(); + } catch (Exception e) { + //e.printStackTrace(); + //LogUtil.error(SysCommon.class, "Get Data File failed:"+e.getMessage()); + } finally { + try { + if (bufferedReader != null) { + bufferedReader.close(); + } + if(fileReader!=null) { + fileReader.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + //-- + return fileContent; + } + public static AppServerState refreshAppServerState() { + AppServerState currentState = new AppServerState(); + currentState.setServerIp(SysCommon.serverIp); + currentState.setHostName(SysCommon.serverName); + currentState.setServerType("MOBILE"); + currentState.setApiDebugLog(SysCommon.apiDebugLog); + currentState.setDbDebugLog(SysCommon.dbDebugLog); + currentState.setAppDebugLog(SysCommon.appDebugLog); + appServerStates.put(currentState.getServerType()+"-"+SysCommon.serverIp, currentState); + return currentState; + } + + public static void registerServerInfo(AppServerState serverInfo) { + if(serverInfo!=null && (!Strings.CS.equals(serverIp, serverInfo.getServerIp()) || !Strings.CS.equals("MOBILE", serverInfo.getServerType()) )) { + appServerStates.put(serverInfo.getServerType()+"-"+serverInfo.getServerIp(), serverInfo); + } + } + + public static AppServerState updateCfgByRequest(AppSettingMsgData updateRequest) { + if(updateRequest!=null) { + List cfgItems = updateRequest.getConfigItems(); + if(cfgItems!=null) { + for(UpdateCfgItem cfgItem:cfgItems) { + if(Strings.CS.equals("dbDebugLog", cfgItem.getCfgItemKey())) { + SysCommon.dbDebugLog= Boolean.parseBoolean(cfgItem.getCfgItemValue()); + }else if(Strings.CS.equals("apiDebugLog", cfgItem.getCfgItemKey())) { + SysCommon.apiDebugLog= Boolean.parseBoolean(cfgItem.getCfgItemValue()); + }else if(Strings.CS.equals("appDebugLog", cfgItem.getCfgItemKey())) { + SysCommon.appDebugLog= Boolean.parseBoolean(cfgItem.getCfgItemValue()); + } + } + } + } + return refreshAppServerState(); + } + + public static LoginUserInfo parseUserFromToken(HttpServletRequest request) { + LoginUserInfo loginUser = null; + String token = request.getHeader("Authorization"); + if(StringUtils.isNotBlank(token)) { + try { +// token = token.substring(6); + loginUser = parseUserFromToken(token); + }catch(Exception err) { + LogUtil.error(SysCommon.class, "Parse Token failed:"+err.getMessage()); + loginUser =null; + } + } + return loginUser; + } + + public static LoginUserInfo parseUserFromToken(String tokenContent) { + LoginUserInfo loginUser = null; + if(StringUtils.isNotBlank(tokenContent)) { + try { + tokenContent = tokenContent.replace("Bearer ", ""); + + DecodedJWT decodeData = JWT.decode(tokenContent); + loginUser = new LoginUserInfo(); + String userId = decodeData.getSubject(); + if(StringUtils.isNotBlank(userId)) { + loginUser.setId(Long.parseLong(userId)); + }else { + loginUser.setId(-1L); + } + loginUser.setLoginId(decodeData.getClaim("login_id").asString()); + loginUser.setGroupName(decodeData.getClaim("user_group").asString()); + }catch(Exception err) { + LogUtil.error(SysCommon.class, "Parse Token failed:"+err.getMessage()); + loginUser =null; + } + } + return loginUser; + } + public static void loadSecurityConfig(String allowOrigins) { + if(allowOrigins!=null) { + String[] serverLists = allowOrigins.split(","); + if(serverLists!=null) { + for(String item:serverLists) { + if(StringUtils.isNotBlank(item)) { + addAllowOriginSource(item.trim()); + } + } + } + } + } + + public static void addAllowOriginSource(String srcServer) { + allowOriginSource.add(srcServer); + } + + public static boolean isAllowOriginSource(String srcServer) { + boolean isAllow = false; + if(StringUtils.isNotBlank(srcServer)) { + for(String allowItem:allowOriginSource) { + if(Strings.CI.startsWith(srcServer, allowItem)) { + isAllow=true; + break; + } + } + } + return isAllow; + } + + public static void loadSoapServerConfig(String soapConfig) { + if(soapConfig!=null) { + String[] serverLists = soapConfig.split(","); + if(serverLists!=null) { + for(String item:serverLists) { + if(StringUtils.isNotBlank(item)) { + addSoapServer(item.trim()); + } + } + } + } + } + + public static void addSoapServer(String srcServer) { + soapServers.add(srcServer); + } + + public static boolean isAllowSoapServer(String srcServer) { + boolean isAllow = false; + if(StringUtils.isNotBlank(srcServer)) { + for(String allowItem:soapServers) { + if(Strings.CI.startsWith(srcServer, allowItem)) { + isAllow=true; + break; + } + } + } + return isAllow; + } + + public static void loadApiServerConfig(String apiServerConfig) { + if(apiServerConfig!=null) { + String[] serverLists = apiServerConfig.split(","); + if(serverLists!=null) { + for(String item:serverLists) { + if(StringUtils.isNotBlank(item)) { + addApiServer(item.trim()); + } + } + } + } + } + + public static void addApiServer(String srcServer) { + httpApiServers.add(srcServer); + } + + public static boolean isAllowApiServer(String srcServer) { + boolean isAllow = false; + if(StringUtils.isNotBlank(srcServer)) { + for(String allowItem:httpApiServers) { + if(Strings.CI.startsWith(srcServer, allowItem)) { + isAllow=true; + break; + } + } + } + return isAllow; + } + + public static void loadAllowIPConfig(String allowIPConfig) { + if(allowIPConfig!=null) { + String[] ipLists = allowIPConfig.split(","); + if(ipLists!=null) { + for(String item:ipLists) { + if(StringUtils.isNotBlank(item)) { + addAllowIP(item.trim()); + } + } + } + } + } + + public static void addAllowIP(String allowIP) { + allowIPSource.add(allowIP); + } + + public static boolean isAllowIPSource(String ip) { + boolean isAllow = false; + if(StringUtils.isNotBlank(ip)) { + for(String allowItem:allowIPSource) { + LogUtil.info(BookingService.class,"[isAllowIPSource]allow item:"+allowItem); + if(Strings.CI.startsWith(ip, allowItem)) { + isAllow=true; + break; + } + } + } + return isAllow; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/constants/SysConstants.java b/src/main/java/com/mgm/mcrm/common/constants/SysConstants.java new file mode 100644 index 0000000..f3b28a3 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/constants/SysConstants.java @@ -0,0 +1,30 @@ +package com.mgm.mcrm.common.constants; + +import org.apache.commons.lang3.StringUtils; + +public class SysConstants { + + public static final String CURRENT_USER_KEY = "currentUser"; + public static final String SUPER_ADMIN_ID ="1"; + + // cfg_settings + public static final String MAX_BOOKING_STAY_DAYS="MAX_BOOKING_STAY_DAYS"; + public static final String MAX_ADVANCE_BOOKING_DAYS="MAX_ADVANCE_BOOKING_DAYS"; + public static final String NUM_OF_MULTIPLE_DATE_RANGE="NUM_OF_MULTIPLE_DATE_RANGE"; + public static final String PROTECTION_PERIOD_CHECKIN="PROTECTION_PERIOD_CHECKIN"; + public static final String PROTECTION_PERIOD_CHECKOUT="PROTECTION_PERIOD_CHECKOUT"; + public static final String PROTECT_PERIOD_ENABLE="PROTECT_PERIOD_ENABLE"; + public static final String MAX_OPERA_BOOKING_DAYS="MAX_OPERA_BOOKING_DAYS"; + public static final String MGM_EMAIL_ADDRESS="MGM_EMAIL_ADDRESS"; + public static final String MACAU_IP="MACAU_IP"; + + public static final int CMS_TOKEN_TYPE=0; + public static final int MOBILE_TOKEN_TYPE=1; + + public static final String PERMISSION_APP_VIEW_BOOKING="10001_01"; + public static final String PERMISSION_APP_NEW_BOOKING="10001_02"; + 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"; + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/BaseApiResponse.java b/src/main/java/com/mgm/mcrm/common/dtos/BaseApiResponse.java new file mode 100644 index 0000000..ec5ba99 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/BaseApiResponse.java @@ -0,0 +1,264 @@ +package com.mgm.mcrm.common.dtos; + +import com.alibaba.fastjson.JSONObject; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +public class BaseApiResponse { + + @Schema(description = "Indicate API success status") + private boolean success = false; + + @Schema(description = "Status Code of response",example="200") + private String code; + + @Schema(description = "Description of result") + private String message; + + @Schema(description = "Data of response") + private T data; + + private String logMessage; + + private Object requestData; + + @Override + public String toString() { + String dataStr=""; + try { + JSONObject objJson = new JSONObject(); + objJson.put("success", success); + objJson.put("code", success); + objJson.put("message", message); + objJson.put("data", data); + dataStr = objJson.toString(); + }catch(Exception ignored){ + + } + return dataStr; + } + + /** + * 成功响应,默认状态码为 "200",默认消息为空字符串 + * @return 包含成功状态和默认消息的 BaseApiResponse 对象 + * @param 响应数据类型 + */ + public static BaseApiResponse ok(){ + return BaseApiResponse.ok(null,null); + } + + /** + * 成功响应,默认状态码为 "200",自定义消息 + * @param message 自定义消息 + * @return 包含成功状态和自定义消息的 BaseApiResponse 对象 + * @param 响应数据类型 + */ + public static BaseApiResponse ok(String message){ + return BaseApiResponse.ok(message, null); + } + + /** + * 成功响应,默认状态码为 "200",自定义数据 + * 当泛型是String时,调用的是success(String message)方法 + * @param data 自定义数据 + * @return 包含成功状态和自定义数据的 BaseApiResponse 对象 + * @param 响应数据类型 + */ + public static BaseApiResponse ok(T data){ + return BaseApiResponse.ok(null, data); + } + + /** + * 成功响应,默认状态码为 "200",自定义消息和数据 + * @param message 自定义消息 + * @param data 自定义数据 + * @return 包含成功状态、自定义消息和数据的 BaseApiResponse 对象 + * @param 响应数据类型 + */ + public static BaseApiResponse ok(String message, T data){ + return build(true, "200", message, data); + } + + /** + * 请求参数错误 + * @param message 错误信息 + * @return 包含错误信息的 BaseApiResponse 对象 + * @param 响应数据类型 + */ + public static BaseApiResponse badRequestError(String message){ + return BaseApiResponse.error("400", message); + } + + /** + * 未登录 + * @param message 错误信息 + * @return 包含错误信息的 BaseApiResponse 对象 + * @param 响应数据类型 + */ + public static BaseApiResponse unauthorizedError(String message){ + return BaseApiResponse.error("401", message); + } + + /** + * 没有权限访问 + * @param message 错误信息 + * @return 包含错误信息的 BaseApiResponse 对象 + * @param 响应数据类型 + */ + public static BaseApiResponse forbiddenError(String message){ + return BaseApiResponse.error("403", message); + } + + /** + * 找不到资源 + * @param message 错误信息 + * @return 包含错误信息的 BaseApiResponse 对象 + * @param 响应数据类型 + */ + public static BaseApiResponse notFoundError(String message){ + return BaseApiResponse.error("404", message); + } + + /** + * 资源冲突,如资源被其他资源使用时 或 资源状态禁用但有其他资源想使用 + * @param message 错误信息 + * @return 包含错误信息的 BaseApiResponse 对象 + * @param 响应数据类型 + */ + public static BaseApiResponse conflictError(String message){ + return BaseApiResponse.error("409", message); + } + + /** + * 资源原本存在,但现在已被删除 + * @param message 错误信息 + * @return 包含错误信息的 BaseApiResponse 对象 + * @param 响应数据类型 + */ + public static BaseApiResponse goneError(String message){ + return BaseApiResponse.error("410", message); + } + + /** + * 服务器内部错误 + * @param message 错误信息 + * @return 包含错误信息的 BaseApiResponse 对象 + * @param 响应数据类型 + */ + public static BaseApiResponse internalServerError(String message){ + return BaseApiResponse.error("500", message); + } + + /** + * 未实现,表示服务器当前不支持请求所需的功能 + * @param message 错误信息 + * @return 包含错误信息的 BaseApiResponse 对象 + * @param 响应数据类型 + */ + public static BaseApiResponse noImplementedError(String message){ + return BaseApiResponse.error("501", message); + } + + /** + * socket连接超时 + * @param message 错误信息 + * @return 包含错误信息的 BaseApiResponse 对象 + * @param 响应数据类型 + */ + public static BaseApiResponse serverUnavailableError(String message){ + return BaseApiResponse.error("503", message); + } + + /** + * socket连接超时 + * @param message 错误信息 + * @return 包含错误信息的 BaseApiResponse 对象 + * @param 响应数据类型 + */ + public static BaseApiResponse socketTimeoutError(String message){ + return BaseApiResponse.error("504", message); + } + + /** + * 自定义构建错误响应信息 + * @param code 错误编码 + * @param message 错误信息 + * @return 包含错误信息的 BaseApiResponse 对象 + * @param 响应数据类型 + */ + public static BaseApiResponse error(String code, String message){ + return build(false, code, message); + } + + /** + * 自定义构建错误响应信息,只返回数据 + * @param data 错误数据 + * @return 包含错误数据的 BaseApiResponse 对象 + * @param 响应数据类型 + */ + public static BaseApiResponse error(T data){ + return build(false, null, null, data); + } + + /** + * 自定义构建响应信息 + * @param code 编码 + * @param message 信息 + * @return BaseApiResponse 对象 + * @param 响应数据类型 + */ + + public static BaseApiResponse build(boolean success, String code, String message){ + return build(success, code, message, null); + } + + /** + * 自定义构建响应信息 + * @param code 编码 + * @param message 信息 + * @return BaseApiResponse 对象 + * @param 响应数据类型 + */ + + public static BaseApiResponse build(boolean success, String code, String message, T Data){ + BaseApiResponse response = new BaseApiResponse<>(); + response.setSuccess(success); + response.setCode(code); + response.setMessage(message); + response.setData(Data); + return response; + } + + /** + * 是否成功响应 + * @return 是否成功响应 + */ + public boolean checkSuccess(){ + // 现在成功码只有200,有些地方success会是true,但是code不一定是200,如有需要,另写方案 + return this.success && "200".equals(code); + } + + /** + * 是否错误响应 + * @return 是否错误响应 + */ + public boolean checkFailed(){ + return !checkSuccess(); + } + + /** + * 将一个BaseApiResponse的信息转换成另一个BaseApiResponse对象,两个对象可能泛型不同,因此不转换Data对象 + * @param original 转换源 + * @return 转换结果 + * @param 结果泛型 + */ + public static BaseApiResponse convert(BaseApiResponse original){ + return build(original.isSuccess(), original.getCode(), original.getMessage(), null); + } + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/BaseQueryRequest.java b/src/main/java/com/mgm/mcrm/common/dtos/BaseQueryRequest.java new file mode 100644 index 0000000..89349d5 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/BaseQueryRequest.java @@ -0,0 +1,53 @@ +package com.mgm.mcrm.common.dtos; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +public class BaseQueryRequest { + private int startRow = -1; + private int endRow = -1; + + public int getPageSize() { + validatePageInfo(); + return pageSize; + } + + public int getPageNo() { + validatePageInfo(); + return pageNo; + } + + private int pageSize = -1; + private int pageNo=-1; + private String sortOrder; + private boolean pageInfoValidated=false; + + private void validatePageInfo() { + if(pageInfoValidated) + return; + if(pageSize<0){ + if(startRow>=0 && endRow>=0){ + pageSize=endRow-startRow; + }else{ + pageSize=20; + } + } + if(pageNo<=0){ + if(startRow>=0){ + pageNo = (startRow+1)/pageSize; + if(pageNo<0) { + pageNo=0; + } + }else{ + pageNo=0; + } + }else{ + pageNo--; + } + pageInfoValidated=true; + } +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/common/dtos/CachedToken.java b/src/main/java/com/mgm/mcrm/common/dtos/CachedToken.java new file mode 100644 index 0000000..d96703a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/CachedToken.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.common.dtos; + +import com.mgm.mcrm.basesetting.property.dtos.response.TokenResponse; + +public class CachedToken { + private final TokenResponse token; + private final long expireTime; + + public CachedToken(TokenResponse token, long expireTime) { + this.token = token; + this.expireTime = expireTime; + } + + public TokenResponse getToken() { + return token; + } + + public boolean isExpired() { + return System.currentTimeMillis() > expireTime; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/DataTableResult.java b/src/main/java/com/mgm/mcrm/common/dtos/DataTableResult.java new file mode 100644 index 0000000..4b74052 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/DataTableResult.java @@ -0,0 +1,13 @@ +package com.mgm.mcrm.common.dtos; + +import lombok.Data; + +import java.util.List; + +@Data +public class DataTableResult { + private List rowData; + private int pageSize=10; + private long totalRecords=0; + private long startRow = 0; +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/EumnApprovalStatus.java b/src/main/java/com/mgm/mcrm/common/dtos/EumnApprovalStatus.java new file mode 100644 index 0000000..0e61f31 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/EumnApprovalStatus.java @@ -0,0 +1,66 @@ +package com.mgm.mcrm.common.dtos; + +public enum EumnApprovalStatus { + + PendingA("PENDING","PA"), + PendingN("PENDING","PN"), + Pending("PENDING","P"), + PApproved("APPROVED","A"), + PRejected("REJECTED","R"), + NApproved("APPROVED","N"), + EPending("EDIT_PENDING","E"), + ERejected("EDIT_REJECTED","D"), + EApproved("EDIT_APPROVED","F"), + WPending("Pending","W"), + WReject("Reject","WR"), + WApproved("Approved","WA"), + WReserved("Reserved","WF"), + WCancelled("Cancelled","WC"); + + private String key; + private String value; + + private EumnApprovalStatus(String key, String value) { + this.key = key; + this.value = value; + } + + public String getKey() { + return key; + } + + public String getValue() { + return value; + } + + public static String getApprovalStatusByDBValue(String value) { + EumnApprovalStatus[] objs = values(); + for (EumnApprovalStatus obj : objs) { + if (obj.getValue().equals(value)) { + return obj.getKey(); + } + } + return "UNKNOWN"; + } + + public static String getDBValueByApprovalStatus(String key) { + EumnApprovalStatus[] objs = values(); + for (EumnApprovalStatus obj : objs) { + if (obj.getKey().equals(key)) { + return obj.getValue(); + } + } + return null; + } + + public static boolean isInclude(String value){ + boolean include = false; + for (EumnApprovalStatus e: EumnApprovalStatus.values()){ + if(e.getValue().equals(value)){ + include = true; + break; + } + } + return include; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/HttpResult.java b/src/main/java/com/mgm/mcrm/common/dtos/HttpResult.java new file mode 100644 index 0000000..4e5478e --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/HttpResult.java @@ -0,0 +1,69 @@ +package com.mgm.mcrm.common.dtos; + +import lombok.Data; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.ProtocolVersion; +import org.apache.hc.core5.http.message.StatusLine; + +import java.io.Serializable; + +@Data +public class HttpResult implements Serializable { + /** + * 执行结果-body + */ + private String result; + + /** + * 状态码-statusCode + */ + private int statusCode; + + /** + * 状态行-StatusLine + */ + private StatusLine statusLine; + + /** + * 请求头信息 + */ + private Header[] reqHeaders; + + /** + * 响应头信息 + */ + private Header[] respHeaders; + + /** + * 协议版本 + */ + private ProtocolVersion protocolVersion; + + /** + * HttpResponse结果对象 + */ + private HttpResponse resp; + + public HttpResult(HttpResponse resp) { + // HttpClient 5 API: 使用 new StatusLine(response) 创建 StatusLine + this.statusLine = new StatusLine(resp); + // HttpClient 5 API: 使用 getHeaders() 获取所有响应头 + this.respHeaders = resp.getHeaders(); + // HttpClient 5 API: 从 StatusLine 获取协议版本 + this.protocolVersion = this.statusLine.getProtocolVersion(); + // HttpClient 5 API: 使用 getCode() 获取状态码 + this.statusCode = resp.getCode(); + this.resp = resp; + } + + /** + * 从返回的头信息中查询指定头信息 + * + * @param name 头信息名称 + */ + public Header getHeaders(final String name) { + Header[] headers = this.resp.getHeaders(name); + return headers!=null && headers.length>0?headers[0]:null; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/RequestDefination.java b/src/main/java/com/mgm/mcrm/common/dtos/RequestDefination.java new file mode 100644 index 0000000..323bdde --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/RequestDefination.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.common.dtos; + +import java.util.List; +import java.util.Map; + +public class RequestDefination { + private Map> requestUrlList; + private Map sampleJson; + public Map> getRequestUrlList() { + return requestUrlList; + } + public void setRequestUrlList(Map> requestUrlList) { + this.requestUrlList = requestUrlList; + } + public Map getSampleJson() { + return sampleJson; + } + public void setSampleJson(Map sampleJson) { + this.sampleJson = sampleJson; + } +} 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 new file mode 100644 index 0000000..c87dfc2 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/config/APIConfig.java @@ -0,0 +1,276 @@ +package com.mgm.mcrm.common.dtos.config; + +public class APIConfig { + + private boolean isLoaded = false; + //-- ESB Server + private String serverUrl_ESB= ""; + private String apiKey_ESB=""; + private String apiSecret_ESB=""; + private int timeout_ESB=0; + + private String serverUrl_ESB_Daylight=""; + private String apiKey_ESB_Daylight=""; + private String apiSecret_ESB_Daylight=""; + private int timeout_ESB_Daylight=0; + + //-- OWS Server + private String serverUrl_OWS= ""; + private int timeout_OWS=0; + + //-- RPA Server + private String serverLoginUrl_RPA= ""; + private String apiAccessName_RPA=""; + private String apiAccessPassword_RPA=""; + private String apiAccessKey_RPA=""; + private String serverAddUrl_RPA= ""; + private String serverExtensionUrl_RPA= ""; + private int timeout_RPA=0; + + //-- SSO Server + private String serverUrl_SSO= ""; + private String clientId_SSO=""; + private String clientSecret_SSO=""; + private int timeout_SSO=0; + + //-- CallCenter Server + private String serverUrl_CallCenter= ""; + private int timeout_CallCenter=0; + + //SMS Config + private String tokenUrl_SMS= ""; + private String sendUrl_SMS= ""; + private String username_SMS= ""; + private String password_SMS= ""; + private String account_SMS= ""; + private String priority_SMS= ""; + + //SMTP Config + private String port_SMTP= ""; + private String host_SMTP= ""; + private String username_SMTP= ""; + 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/data_import/ValidateResult.java b/src/main/java/com/mgm/mcrm/common/dtos/data_import/ValidateResult.java new file mode 100644 index 0000000..7163bc2 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/data_import/ValidateResult.java @@ -0,0 +1,49 @@ +package com.mgm.mcrm.common.dtos.data_import; + +import java.util.List; + +public class ValidateResult { + private int resultCount=0; + private int passedCount=0; + private int failedCount=0; + private boolean success=false; + private List resultRows; + private List groupItems=null; + public int getResultCount() { + return resultCount; + } + public void setResultCount(int resultCount) { + this.resultCount = resultCount; + } + public int getPassedCount() { + return passedCount; + } + public void setPassedCount(int passedCount) { + this.passedCount = passedCount; + } + public int getFailedCount() { + return failedCount; + } + public void setFailedCount(int failedCount) { + this.failedCount = failedCount; + } + public boolean isSuccess() { + return success; + } + public void setSuccess(boolean success) { + this.success = success; + } + public List getResultRows() { + return resultRows; + } + public void setResultRows(List resultRows) { + this.resultRows = resultRows; + } + public List getGroupItems() { + return groupItems; + } + public void setGroupItems(List groupItems) { + this.groupItems = groupItems; + } + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/data_import/booking/OtherBookingImportRow.java b/src/main/java/com/mgm/mcrm/common/dtos/data_import/booking/OtherBookingImportRow.java new file mode 100644 index 0000000..8587eb0 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/data_import/booking/OtherBookingImportRow.java @@ -0,0 +1,38 @@ +package com.mgm.mcrm.common.dtos.data_import.booking; + +import lombok.Data; + +@Data +public class OtherBookingImportRow { + + private boolean validatePassed=false; + private String errorMessage; + + private Long otherRoomStatusId; + private Long otherFollowUpStatusId; + private Long propertyId; + private Long roomId; + private Long bookingTypeId; + private Long marketCodeId; + private Long segmentId; + private Long souceCodeId; + private String otherRoomStatusName; + private String otherFollowUpStatusName; + private String propertyName; + private String roomName; + private String bookingTypeName; + private String marketCodeName; + private String segmentName; + private String checkinDate; + private String checkoutDate; + private String playerId; + private String bookerId; + private String approverId; + private String sharer; + private String remark; + private String sharerList; + private String confirmationNo; + private String playerName; + private String sourceCodeName; + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/excel_export/ColumnDefine.java b/src/main/java/com/mgm/mcrm/common/dtos/excel_export/ColumnDefine.java new file mode 100644 index 0000000..efecda2 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/excel_export/ColumnDefine.java @@ -0,0 +1,34 @@ +package com.mgm.mcrm.common.dtos.excel_export; + +public class ColumnDefine { + private String columnHeader; + private String dataType; + private String attrName; + private int columnWidth=0; + + public String getColumnHeader() { + return columnHeader; + } + public void setColumnHeader(String columnHeader) { + this.columnHeader = columnHeader; + } + public String getDataType() { + return dataType; + } + public void setDataType(String dataType) { + this.dataType = dataType; + } + public String getAttrName() { + return attrName; + } + public void setAttrName(String attrName) { + this.attrName = attrName; + } + public int getColumnWidth() { + return columnWidth; + } + public void setColumnWidth(int columnWidth) { + this.columnWidth = columnWidth; + } + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/excel_export/DataElement.java b/src/main/java/com/mgm/mcrm/common/dtos/excel_export/DataElement.java new file mode 100644 index 0000000..7af5a93 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/excel_export/DataElement.java @@ -0,0 +1,85 @@ +package com.mgm.mcrm.common.dtos.excel_export; + +import java.util.List; + +public class DataElement { + private int offsetRow=0; + private int offsetCol=0; + private int elementType=0; + private boolean isShowHeader=false; + private String objClassName; + private String headerAlign="center"; + private String headerColor=""; + private String textAlign="left"; + private String textColor=""; + private List columnDefs; + private List blockData; + + public int getElementType() { + return elementType; + } + public void setElementType(int elementType) { + this.elementType = elementType; + } + public List getColumnDefs() { + return columnDefs; + } + public void setColumnDefs(List columnDefs) { + this.columnDefs = columnDefs; + } + + public boolean isShowHeader() { + return isShowHeader; + } + public void setShowHeader(boolean isShowHeader) { + this.isShowHeader = isShowHeader; + } + public int getOffsetRow() { + return offsetRow; + } + public void setOffsetRow(int offsetRow) { + this.offsetRow = offsetRow; + } + public int getOffsetCol() { + return offsetCol; + } + public void setOffsetCol(int offsetCol) { + this.offsetCol = offsetCol; + } + public String getObjClassName() { + return objClassName; + } + public void setObjClassName(String objClassName) { + this.objClassName = objClassName; + } + public String getHeaderAlign() { + return headerAlign; + } + public void setHeaderAlign(String headerAlign) { + this.headerAlign = headerAlign; + } + public String getHeaderColor() { + return headerColor; + } + public void setHeaderColor(String headerColor) { + this.headerColor = headerColor; + } + public String getTextAlign() { + return textAlign; + } + public void setTextAlign(String textAlign) { + this.textAlign = textAlign; + } + public String getTextColor() { + return textColor; + } + public void setTextColor(String textColor) { + this.textColor = textColor; + } + public List getBlockData() { + return blockData; + } + public void setBlockData(List blockData) { + this.blockData = blockData; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/excel_export/ExportDefination.java b/src/main/java/com/mgm/mcrm/common/dtos/excel_export/ExportDefination.java new file mode 100644 index 0000000..53d3881 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/excel_export/ExportDefination.java @@ -0,0 +1,24 @@ +package com.mgm.mcrm.common.dtos.excel_export; + +import java.util.List; + +public class ExportDefination { + private List exportPages; + private String exportFileName; + + public List getExportPages() { + return exportPages; + } + + public void setExportPages(List exportPages) { + this.exportPages = exportPages; + } + + public String getExportFileName() { + return exportFileName; + } + + public void setExportFileName(String exportFileName) { + this.exportFileName = exportFileName; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/excel_export/ExportSheet.java b/src/main/java/com/mgm/mcrm/common/dtos/excel_export/ExportSheet.java new file mode 100644 index 0000000..e37a7d6 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/excel_export/ExportSheet.java @@ -0,0 +1,26 @@ +package com.mgm.mcrm.common.dtos.excel_export; + +import java.util.List; + +public class ExportSheet { + private String sheetName; + private List dataElements; + + public ExportSheet() { + + } + + public String getSheetName() { + return sheetName; + } + public void setSheetName(String sheetName) { + this.sheetName = sheetName; + } + public List getDataElements() { + return dataElements; + } + public void setDataElements(List dataElements) { + this.dataElements = dataElements; + } + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/excel_model/ColumnDefine.java b/src/main/java/com/mgm/mcrm/common/dtos/excel_model/ColumnDefine.java new file mode 100644 index 0000000..99f6232 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/excel_model/ColumnDefine.java @@ -0,0 +1,99 @@ +package com.mgm.mcrm.common.dtos.excel_model; + +import java.util.List; + +public class ColumnDefine { + private String columnHeader; + private String columnType="SINGLE"; + private String dataType="String"; + private String attrName; + private String groupName; + private String textAlign; + private String formatVal; + private String groupKeyAttrName; + private boolean checkHeader=false; + private int columnWidth=0; + private int columnIndex=0; + private int headerRowIdx=0; + private List groupColumns=null; + + public String getColumnHeader() { + return columnHeader; + } + public void setColumnHeader(String columnHeader) { + this.columnHeader = columnHeader; + } + public String getDataType() { + return dataType; + } + public void setDataType(String dataType) { + this.dataType = dataType; + } + public String getAttrName() { + return attrName; + } + public void setAttrName(String attrName) { + this.attrName = attrName; + } + public int getColumnWidth() { + return columnWidth; + } + public void setColumnWidth(int columnWidth) { + this.columnWidth = columnWidth; + } + public int getColumnIndex() { + return columnIndex; + } + public void setColumnIndex(int columnIndex) { + this.columnIndex = columnIndex; + } + public String getColumnType() { + return columnType; + } + public void setColumnType(String columnType) { + this.columnType = columnType; + } + public String getTextAlign() { + return textAlign; + } + public void setTextAlign(String textAlign) { + this.textAlign = textAlign; + } + public String getFormatVal() { + return formatVal; + } + public void setFormatVal(String formatVal) { + this.formatVal = formatVal; + } + public boolean isCheckHeader() { + return checkHeader; + } + public void setCheckHeader(boolean checkHeader) { + this.checkHeader = checkHeader; + } + public int getHeaderRowIdx() { + return headerRowIdx; + } + public void setHeaderRowIdx(int headerRowIdx) { + this.headerRowIdx = headerRowIdx; + } + public List getGroupColumns() { + return groupColumns; + } + public void setGroupColumns(List groupColumns) { + this.groupColumns = groupColumns; + } + public String getGroupName() { + return groupName; + } + public void setGroupName(String groupName) { + this.groupName = groupName; + } + public String getGroupKeyAttrName() { + return groupKeyAttrName; + } + public void setGroupKeyAttrName(String groupKeyAttrName) { + this.groupKeyAttrName = groupKeyAttrName; + } + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/excel_model/ColumnGroupInfo.java b/src/main/java/com/mgm/mcrm/common/dtos/excel_model/ColumnGroupInfo.java new file mode 100644 index 0000000..0df2906 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/excel_model/ColumnGroupInfo.java @@ -0,0 +1,57 @@ +package com.mgm.mcrm.common.dtos.excel_model; + +import java.lang.reflect.Field; +import java.util.List; + +public class ColumnGroupInfo { + + private String groupName; + private int colStartIndex=0; + private Field groupDataField=null; + private Field keyField=null; + private Class groupDataType=null; + private List groupItems=null; + private List groupColumns; + public String getGroupName() { + return groupName; + } + public void setGroupName(String groupName) { + this.groupName = groupName; + } + public int getColStartIndex() { + return colStartIndex; + } + public void setColStartIndex(int colStartIndex) { + this.colStartIndex = colStartIndex; + } + public List getGroupColumns() { + return groupColumns; + } + public void setGroupColumns(List groupColumns) { + this.groupColumns = groupColumns; + } + public Field getGroupDataField() { + return groupDataField; + } + public void setGroupDataField(Field groupDataField) { + this.groupDataField = groupDataField; + } + public Class getGroupDataType() { + return groupDataType; + } + public void setGroupDataType(Class groupDataType) { + this.groupDataType = groupDataType; + } + public List getGroupItems() { + return groupItems; + } + public void setGroupItems(List groupItems) { + this.groupItems = groupItems; + } + public Field getKeyField() { + return keyField; + } + public void setKeyField(Field keyField) { + this.keyField = keyField; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/excel_model/DataBlock.java b/src/main/java/com/mgm/mcrm/common/dtos/excel_model/DataBlock.java new file mode 100644 index 0000000..cc2f2da --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/excel_model/DataBlock.java @@ -0,0 +1,100 @@ +package com.mgm.mcrm.common.dtos.excel_model; + +import java.util.List; + +public class DataBlock { + private int offsetRow=0; + private int offsetCol=0; + private int elementType=0; + private int headerRowNum=1; + private boolean isShowHeader=false; + private String objClassName; + private String headerAlign="center"; + private String headerColor=""; + private String textAlign="left"; + private String textColor=""; + private String headerTextColor=""; + private String blockName=""; + private List columnDefs; + + + public int getElementType() { + return elementType; + } + public void setElementType(int elementType) { + this.elementType = elementType; + } + public List getColumnDefs() { + return columnDefs; + } + public void setColumnDefs(List columnDefs) { + this.columnDefs = columnDefs; + } + + public boolean isShowHeader() { + return isShowHeader; + } + public void setShowHeader(boolean isShowHeader) { + this.isShowHeader = isShowHeader; + } + public int getOffsetRow() { + return offsetRow; + } + public void setOffsetRow(int offsetRow) { + this.offsetRow = offsetRow; + } + public int getOffsetCol() { + return offsetCol; + } + public void setOffsetCol(int offsetCol) { + this.offsetCol = offsetCol; + } + public String getObjClassName() { + return objClassName; + } + public void setObjClassName(String objClassName) { + this.objClassName = objClassName; + } + public String getHeaderAlign() { + return headerAlign; + } + public void setHeaderAlign(String headerAlign) { + this.headerAlign = headerAlign; + } + public String getHeaderColor() { + return headerColor; + } + public void setHeaderColor(String headerColor) { + this.headerColor = headerColor; + } + public String getTextAlign() { + return textAlign; + } + public void setTextAlign(String textAlign) { + this.textAlign = textAlign; + } + public String getTextColor() { + return textColor; + } + public void setTextColor(String textColor) { + this.textColor = textColor; + } + public String getBlockName() { + return blockName; + } + public void setBlockName(String blockName) { + this.blockName = blockName; + } + public String getHeaderTextColor() { + return headerTextColor; + } + public void setHeaderTextColor(String headerTextColor) { + this.headerTextColor = headerTextColor; + } + public int getHeaderRowNum() { + return headerRowNum; + } + public void setHeaderRowNum(int headerRowNum) { + this.headerRowNum = headerRowNum; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/excel_model/ExportDefine.java b/src/main/java/com/mgm/mcrm/common/dtos/excel_model/ExportDefine.java new file mode 100644 index 0000000..d9967c0 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/excel_model/ExportDefine.java @@ -0,0 +1,34 @@ +package com.mgm.mcrm.common.dtos.excel_model; + +import java.util.List; + +public class ExportDefine { + private String exportName; + private List exportPages; + private String exportFileName; + + public List getExportPages() { + return exportPages; + } + + public void setExportPages(List exportPages) { + this.exportPages = exportPages; + } + + public String getExportFileName() { + return exportFileName; + } + + public void setExportFileName(String exportFileName) { + this.exportFileName = exportFileName; + } + + public String getExportName() { + return exportName; + } + + public void setExportName(String exportName) { + this.exportName = exportName; + } + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/excel_model/GroupItem.java b/src/main/java/com/mgm/mcrm/common/dtos/excel_model/GroupItem.java new file mode 100644 index 0000000..5b3b24a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/excel_model/GroupItem.java @@ -0,0 +1,27 @@ +package com.mgm.mcrm.common.dtos.excel_model; + +public class GroupItem { + + private String itemText; + private String itemKey; + private int headerIndex=-1; + + public String getItemText() { + return itemText; + } + public void setItemText(String itemText) { + this.itemText = itemText; + } + public String getItemKey() { + return itemKey; + } + public void setItemKey(String itemKey) { + this.itemKey = itemKey; + } + public int getHeaderIndex() { + return headerIndex; + } + public void setHeaderIndex(int headerIndex) { + this.headerIndex = headerIndex; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/excel_model/ImportDefine.java b/src/main/java/com/mgm/mcrm/common/dtos/excel_model/ImportDefine.java new file mode 100644 index 0000000..5567304 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/excel_model/ImportDefine.java @@ -0,0 +1,34 @@ +package com.mgm.mcrm.common.dtos.excel_model; + +import java.util.List; + +public class ImportDefine { + private String importName; + private List importPages; + private String importFileName; + + public List getImportPages() { + return importPages; + } + + public void setImportPages(List exportPages) { + this.importPages = exportPages; + } + + public String getImportFileName() { + return importFileName; + } + + public void setImportFileName(String importFileName) { + this.importFileName = importFileName; + } + + public String getImportName() { + return importName; + } + + public void setImportName(String importName) { + this.importName = importName; + } + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/excel_model/RowFieldInfo.java b/src/main/java/com/mgm/mcrm/common/dtos/excel_model/RowFieldInfo.java new file mode 100644 index 0000000..efb0e79 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/excel_model/RowFieldInfo.java @@ -0,0 +1,73 @@ +package com.mgm.mcrm.common.dtos.excel_model; + +import java.lang.reflect.Field; + +import org.apache.poi.xssf.usermodel.XSSFCellStyle; + +public class RowFieldInfo { + private String fieldKey; + private Field dataField=null; + private String columnHeader=""; + private int headerRowIdx=-1; + private int colIndex=0; + private String dateFormat; + private String dataType="String"; + private boolean checkHeader=false; + private XSSFCellStyle fieldStyle=null; + + public String getFieldKey() { + return fieldKey; + } + public void setFieldKey(String fieldKey) { + this.fieldKey = fieldKey; + } + public Field getDataField() { + return dataField; + } + public void setDataField(Field dataField) { + this.dataField = dataField; + } + public int getColIndex() { + return colIndex; + } + public void setColIndex(int colIndex) { + this.colIndex = colIndex; + } + public XSSFCellStyle getFieldStyle() { + return fieldStyle; + } + public void setFieldStyle(XSSFCellStyle fieldStyle) { + this.fieldStyle = fieldStyle; + } + public boolean isCheckHeader() { + return checkHeader; + } + public void setCheckHeader(boolean checkHeader) { + this.checkHeader = checkHeader; + } + public String getColumnHeader() { + return columnHeader; + } + public void setColumnHeader(String columnHeader) { + this.columnHeader = columnHeader; + } + public int getHeaderRowIdx() { + return headerRowIdx; + } + public void setHeaderRowIdx(int headerRowIdx) { + this.headerRowIdx = headerRowIdx; + } + public String getDateFormat() { + return dateFormat; + } + public void setDateFormat(String dateFormat) { + this.dateFormat = dateFormat; + } + public String getDataType() { + return dataType; + } + public void setDataType(String dataType) { + this.dataType = dataType; + } + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/excel_model/SheetDefine.java b/src/main/java/com/mgm/mcrm/common/dtos/excel_model/SheetDefine.java new file mode 100644 index 0000000..3f6b3b3 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/excel_model/SheetDefine.java @@ -0,0 +1,30 @@ +package com.mgm.mcrm.common.dtos.excel_model; + +import java.util.List; + +public class SheetDefine { + private String sheetName; + private int sheetIndx=0; + private List dataElements; + + public String getSheetName() { + return sheetName; + } + public void setSheetName(String sheetName) { + this.sheetName = sheetName; + } + public List getDataElements() { + return dataElements; + } + public void setDataElements(List dataElements) { + this.dataElements = dataElements; + } + public int getSheetIndx() { + return sheetIndx; + } + public void setSheetIndx(int sheetIndx) { + this.sheetIndx = sheetIndx; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/http_util/HttpRequestDefine.java b/src/main/java/com/mgm/mcrm/common/dtos/http_util/HttpRequestDefine.java new file mode 100644 index 0000000..5048842 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/http_util/HttpRequestDefine.java @@ -0,0 +1,100 @@ +package com.mgm.mcrm.common.dtos.http_util; + +import java.util.Map; + +import org.apache.hc.client5.http.auth.CredentialsProvider; +import org.apache.hc.core5.http.HttpEntity; +import org.springframework.web.multipart.MultipartFile; + + +public class HttpRequestDefine { + + private String requestUrl; + private String requestMethod="GET"; + private int timeout=0; + private String entityContent=""; + private String requestCharSet ="UTF-8"; + private String responseCharSet = "UTF-8"; + private boolean isUpload =false; + private MultipartFile uploadFile = null; + private String fileParaName; + private CredentialsProvider credentials=null; + private HttpEntity requestEntity; + + private Map headers; + + public String getRequestUrl() { + return requestUrl; + } + public void setRequestUrl(String requestUrl) { + this.requestUrl = requestUrl; + } + public String getRequestMethod() { + return requestMethod; + } + public void setRequestMethod(String requestMethod) { + this.requestMethod = requestMethod; + } + public int getTimeout() { + return timeout; + } + public void setTimeout(int timeout) { + this.timeout = timeout; + } + public Map getHeaders() { + return headers; + } + public void setHeaders(Map headers) { + this.headers = headers; + } + public String getEntityContent() { + return entityContent; + } + public void setEntityContent(String entityContent) { + this.entityContent = entityContent; + } + public String getRequestCharSet() { + return requestCharSet; + } + public void setRequestCharSet(String requestCharSet) { + this.requestCharSet = requestCharSet; + } + public String getResponseCharSet() { + return responseCharSet; + } + public void setResponseCharSet(String responseCharSet) { + this.responseCharSet = responseCharSet; + } + + public boolean isUpload() { + return isUpload; + } + public void setUpload(boolean isUpload) { + this.isUpload = isUpload; + } + public MultipartFile getUploadFile() { + return uploadFile; + } + public void setUploadFile(MultipartFile uploadFile) { + this.uploadFile = uploadFile; + } + public String getFileParaName() { + return fileParaName; + } + public void setFileParaName(String fileParaName) { + this.fileParaName = fileParaName; + } + public CredentialsProvider getCredentials() { + return credentials; + } + public void setCredentials(CredentialsProvider credentials) { + this.credentials = credentials; + } + public HttpEntity getRequestEntity() { + return requestEntity; + } + public void setRequestEntity(HttpEntity requestEntity) { + this.requestEntity = requestEntity; + } + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/http_util/HttpResponseResult.java b/src/main/java/com/mgm/mcrm/common/dtos/http_util/HttpResponseResult.java new file mode 100644 index 0000000..5537e27 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/http_util/HttpResponseResult.java @@ -0,0 +1,83 @@ +package com.mgm.mcrm.common.dtos.http_util; + +import org.apache.hc.client5.http.cookie.Cookie; + +import java.util.Date; +import java.util.List; + + +public class HttpResponseResult { + + private int statusCode; + private String responseContent; + private String errorMessage; + private String requestUrl; + private String requestContent; + private String requestTime; + private String responseTime; + private Date requestTimeVal; + private Date responseTimeVal; + private List cookies; + + public int getStatusCode() { + return statusCode; + } + public void setStatusCode(int statusCode) { + this.statusCode = statusCode; + } + public String getResponseContent() { + return responseContent; + } + public void setResponseContent(String responseContent) { + this.responseContent = responseContent; + } + public String getErrorMessage() { + return errorMessage; + } + public void setMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + public String getRequestUrl() { + return requestUrl; + } + public void setRequestUrl(String requestUrl) { + this.requestUrl = requestUrl; + } + public String getRequestContent() { + return requestContent; + } + public void setRequestContent(String requestContent) { + this.requestContent = requestContent; + } + public Date getRequestTimeVal() { + return requestTimeVal; + } + public void setRequestTimeVal(Date requestTimeVal) { + this.requestTimeVal = requestTimeVal; + } + public Date getResponseTimeVal() { + return responseTimeVal; + } + public void setResponseTimeVal(Date responseTimeVal) { + this.responseTimeVal = responseTimeVal; + } + public String getRequestTime() { + return requestTime; + } + public void setRequestTime(String requestTime) { + this.requestTime = requestTime; + } + public String getResponseTime() { + return responseTime; + } + public void setResponseTime(String responseTime) { + this.responseTime = responseTime; + } + public List getCookies() { + return cookies; + } + public void setCookies(List cookies) { + this.cookies = cookies; + } + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/ApprovalGamingDataResult.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/ApprovalGamingDataResult.java new file mode 100644 index 0000000..030205a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/ApprovalGamingDataResult.java @@ -0,0 +1,39 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import com.mgm.mcrm.approval.models.ApprovalGamingData; + +import java.io.Serializable; +import java.util.List; + + +public class ApprovalGamingDataResult implements Serializable { + + private String statusCode = null; + private String statusDescription=null; + private List Records = null; + + + 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 List getRecords() { + return Records; + } + + public void setRecords(List records) { + Records = records; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/ApproverRecord.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/ApproverRecord.java new file mode 100644 index 0000000..e7f6215 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/ApproverRecord.java @@ -0,0 +1,25 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + + +public class ApproverRecord { + + + private String EmployeeId = null; + private String EmployeeName = null; + + public String getEmployeeId() { + return EmployeeId; + } + + public void setEmployeeId(String employeeId) { + EmployeeId = employeeId; + } + + public String getEmployeeName() { + return EmployeeName; + } + + public void setEmployeeName(String employeeName) { + EmployeeName = employeeName; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/ApproverRecordResult.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/ApproverRecordResult.java new file mode 100644 index 0000000..4fa5456 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/ApproverRecordResult.java @@ -0,0 +1,102 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; + +import java.util.ArrayList; +import java.util.List; + +public class ApproverRecordResult { + + + private String PlayerId = null; + private String BookingType = null; + private String Property = null; + private String RoomCategory = null; + private String StartDate = null; + private String EndDate = null; + private String ApprovalRoutingType = null; + private String ApprovalRoutingMessage = null; + private Object ApproverList; + + + public String getPlayerId() { + return PlayerId; + } + + public void setPlayerId(String playerId) { + PlayerId = playerId; + } + + public String getBookingType() { + return BookingType; + } + + public void setBookingType(String bookingType) { + BookingType = bookingType; + } + + public String getProperty() { + return Property; + } + + public void setProperty(String property) { + Property = property; + } + + public String getRoomCategory() { + return RoomCategory; + } + + public void setRoomCategory(String roomCategory) { + RoomCategory = roomCategory; + } + + public String getApprovalRoutingType() { + return ApprovalRoutingType; + } + + public void setApprovalRoutingType(String approvalRoutingType) { + ApprovalRoutingType = approvalRoutingType; + } + + public String getApprovalRoutingMessage() { + return ApprovalRoutingMessage; + } + + public void setApprovalRoutingMessage(String approvalRoutingMessage) { + ApprovalRoutingMessage = approvalRoutingMessage; + } + + public List getApproverList() { + if (ApproverList == null) { + return new ArrayList(); + } + if (ApproverList instanceof JSONArray arr) { + return arr.toJavaList(ApproverRecord.class); + } + if (ApproverList instanceof String s) { + s = s.trim(); + if (s.isEmpty()) { + return new ArrayList(); + } + JSONArray arr = JSONArray.parseArray(s); + return arr == null ? new ArrayList() : arr.toJavaList(ApproverRecord.class); + } + // List/Map 等其它情况:统一转成 JSON 再转回 List + JSONArray arr = JSON.parseArray(JSON.toJSONString(ApproverList)); + return arr == null ? new ArrayList() : arr.toJavaList(ApproverRecord.class); + } + + public void setApproverList(List approverList) { + ApproverList = approverList; + } + + public void setApproverList(String approverList) { + ApproverList = approverList; + } + + public void setApproverList(Object approverList) { + ApproverList = approverList; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/ApproverResult.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/ApproverResult.java new file mode 100644 index 0000000..1a95af6 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/ApproverResult.java @@ -0,0 +1,37 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import java.util.ArrayList; +import java.util.List; + + +public class ApproverResult { + + + private String StatusCode = null; + private String StatusDescription=null; + private List Records = new ArrayList(); + + public String getStatusCode() { + return StatusCode; + } + + public void setStatusCode(String statusCode) { + StatusCode = statusCode; + } + + public String getStatusDescription() { + return StatusDescription; + } + + public void setStatusDescription(String statusDescription) { + StatusDescription = statusDescription; + } + + public List getRecords() { + return Records; + } + + public void setRecords(List records) { + Records = records; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/CheckApproverResult.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/CheckApproverResult.java new file mode 100644 index 0000000..d46b827 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/CheckApproverResult.java @@ -0,0 +1,17 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import lombok.Data; + +@Data +public class CheckApproverResult { + + private String statusCode = null; + private String statusDescription=""; + private String userId; + private String userName; + private String property; + private String roomCategory; + private String roomType; + private String isApprover; + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/ItemRecord.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/ItemRecord.java new file mode 100644 index 0000000..8430761 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/ItemRecord.java @@ -0,0 +1,23 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + + +public class ItemRecord { + + private String ItemRecordDescription = null; + + public ItemRecord() { + + } + + + public String getItemRecordDescription() { + return ItemRecordDescription; + } + + public void setItemRecordDescription(String itemRecordDescription) { + ItemRecordDescription = itemRecordDescription; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/NonMGMBookingApiResult.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/NonMGMBookingApiResult.java new file mode 100644 index 0000000..a0688fd --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/NonMGMBookingApiResult.java @@ -0,0 +1,33 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import java.util.List; + +public class NonMGMBookingApiResult { + + private String statusCode; + private String statusDescription; + private List records; + 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 List getRecords() { + return records; + } + public void setRecords(List records) { + this.records = records; + } + + + + + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/NonMGMBookingRecord.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/NonMGMBookingRecord.java new file mode 100644 index 0000000..85f4580 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/NonMGMBookingRecord.java @@ -0,0 +1,55 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +public class NonMGMBookingRecord { + + private String confirmationNumber; + private String property; + private String roomTypeStatusCode; + private String checkInDate; + private String checkOutDate; + private String createdBy; + private String createdOn; + + public String getConfirmationNumber() { + return confirmationNumber; + } + public void setConfirmationNumber(String confirmationNumber) { + this.confirmationNumber = confirmationNumber; + } + public String getProperty() { + return property; + } + public void setProperty(String property) { + this.property = property; + } + public String getRoomTypeStatusCode() { + return roomTypeStatusCode; + } + public void setRoomTypeStatusCode(String roomTypeStatusCode) { + this.roomTypeStatusCode = roomTypeStatusCode; + } + public String getCheckInDate() { + return checkInDate; + } + public void setCheckInDate(String checkInDate) { + this.checkInDate = checkInDate; + } + public String getCheckOutDate() { + return checkOutDate; + } + public void setCheckOutDate(String checkOutDate) { + this.checkOutDate = checkOutDate; + } + public String getCreatedBy() { + return createdBy; + } + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + public String getCreatedOn() { + return createdOn; + } + public void setCreatedOn(String createdOn) { + this.createdOn = createdOn; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/PlayerProfileEntry.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/PlayerProfileEntry.java new file mode 100644 index 0000000..ea5cd32 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/PlayerProfileEntry.java @@ -0,0 +1,32 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class PlayerProfileEntry { + + 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<>(); + private String profileId; +} + diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/PlayerTPDApiResult.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/PlayerTPDApiResult.java new file mode 100644 index 0000000..26d243f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/PlayerTPDApiResult.java @@ -0,0 +1,66 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.fastjson.JSONObject; + +import com.mgm.mcrm.player.dtos.PlayerTPD; + + +public class PlayerTPDApiResult { + + private String statusCode = null; + private String statusDescription=""; + private List records; + private int status; + private List dates=new ArrayList(); + + public PlayerTPDApiResult() { + + } + + 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 List getRecords() { + return records; + } + + public void setRecords(List records) { + this.records = records; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public List getDates() { + return dates; + } + + public void setDates(List dates) { + this.dates = dates; + } + + + + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDashboardRecord.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDashboardRecord.java new file mode 100644 index 0000000..a4e488a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDashboardRecord.java @@ -0,0 +1,86 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + + +public class TodoDashboardRecord { + + private Integer UserId=null; + private String UserSegment=null; + private String Type = null; + private Integer Identifier = null; + private String ItemName=null; + private Integer Level=null; + private Double CurrentValue = null; + private Double TargetValue = null; + + public TodoDashboardRecord() { + + } + + public Integer getUserId() { + return UserId; + } + + + public void setUserId(Integer userId) { + UserId = userId; + } + + public String getType() { + return Type; + } + + public void setType(String Type) { + this.Type = Type; + } + + public Integer getIdentifier() { + return Identifier; + } + + public void setIdentifier(Integer identifier) { + Identifier = identifier; + } + + public String getItemName() { + return ItemName; + } + + public void setItemName(String itemName) { + ItemName = itemName; + } + + public String getUserSegment() { + return UserSegment; + } + + public void setUserSegment(String userSegment) { + UserSegment = userSegment; + } + + public Integer getLevel() { + return Level; + } + + public void setLevel(Integer level) { + Level = level; + } + + public Double getCurrentValue() { + return CurrentValue; + } + + public void setCurrentValue(Double currentValue) { + CurrentValue = currentValue; + } + + public Double getTargetValue() { + return TargetValue; + } + + public void setTargetValue(Double targetValue) { + TargetValue = targetValue; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDashboardResult.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDashboardResult.java new file mode 100644 index 0000000..73c9eaf --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDashboardResult.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + + +@Data +public class TodoDashboardResult { + + private String statusCode = null; + private String statusDescription=null; + private List records = new ArrayList(); + + public TodoDashboardResult() { + + } + + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDateListRecord.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDateListRecord.java new file mode 100644 index 0000000..46d6099 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDateListRecord.java @@ -0,0 +1,40 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import java.util.ArrayList; +import java.util.List; + + +public class TodoDateListRecord { + + + private String Date = null; + private List dateRecords = new ArrayList(); + + public TodoDateListRecord() { + + } + + + public String getDate() { + return Date; + } + + + public void setDate(String date) { + Date = date; + } + + + public List getDateRecords() { + return dateRecords; + } + + + public void setDateRecords(List dateRecords) { + this.dateRecords = dateRecords; + } + + + + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDateListResult.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDateListResult.java new file mode 100644 index 0000000..5c64acf --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDateListResult.java @@ -0,0 +1,42 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import java.util.ArrayList; +import java.util.List; + + +public class TodoDateListResult { + + + private String statusCode = null; + private String statusDescription=null; + private List Records = new ArrayList(); + + public TodoDateListResult() { + + } + + 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 List getRecords() { + return Records; + } + + public void setRecords(List records) { + Records = records; + } + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDetailDescription.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDetailDescription.java new file mode 100644 index 0000000..0ce3fb7 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDetailDescription.java @@ -0,0 +1,42 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + + +public class TodoDetailDescription { + + + private String ItemRecordType = null; + private Integer ItemRecordId = null; + private String ItemRecordDescription = null; + + public TodoDetailDescription() { + + } + + public String getItemRecordType() { + return ItemRecordType; + } + + public void setItemRecordType(String itemRecordType) { + ItemRecordType = itemRecordType; + } + + public Integer getItemRecordId() { + return ItemRecordId; + } + + public void setItemRecordId(Integer itemRecordId) { + ItemRecordId = itemRecordId; + } + + public String getItemRecordDescription() { + return ItemRecordDescription; + } + + public void setItemRecordDescription(String itemRecordDescription) { + ItemRecordDescription = itemRecordDescription; + } + + + + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDetailResult.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDetailResult.java new file mode 100644 index 0000000..bb936bf --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoDetailResult.java @@ -0,0 +1,63 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.Date; + +@Data +public class TodoDetailResult { + + private String StatusCode = null; + private String StatusDescription=null; + private Integer PlayerId = null; + private Date Date = null; + private String TierName = null; + private String ChineseName = null; + private String EnglishName = null; + private String Salutation = null; + private String Location=null; + private String ActivePrgId=null; + private Integer PrgTO=null; + private Integer PrgWin=null; + private Double TORIPercentage=null; + private Integer FrontMoney=null; + private Integer TTO=null; + + @JsonProperty("01CompBalance") + private Integer ComBalance=null; + + private String R3MTO=null; + private String R3MTOD=null; + private String R3MWin=null; + private String R3MTPD=null; + private String R3MTheo = null; + private String R3MRIPercentage=null; + private String R6MTO=null; + private String R6MTOD=null; + private String R6MWin=null; + private String R6MTPD=null; + private String R6MTheo = null; + private String R6MRIPercentage=null; + private Integer ExpComm=null; + private Integer NetCreditOutstanding=null; + private Integer UnsettledExpenses=null; + private Integer TodayTo=null; + private Integer TodayTPD=null; + private Integer TodayWin=null; + private Integer TodayTheo = null; + private Integer TripWin=null; + private Integer TripTPD=null; + private Integer TripTheo = null; + private Double TripRIPercentage=null; + private Integer YesterdayTO=null; + private Integer YesterdayWin=null; + private Integer YesterdayPlayHour=null; + private Integer AveragePlayHour = null; + private List Descriptions = new ArrayList(); + public TodoDetailResult() { + } +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoListRecord.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoListRecord.java new file mode 100644 index 0000000..18b9bcf --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoListRecord.java @@ -0,0 +1,236 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import java.util.List; + + +public class TodoListRecord { + + private String Date = null; + private String ActionDate = null; + private String OperaConfirmationNo = null; + private Integer PlayerId = null; + private String TierName = null; + private String ChineseName = null; + private String EnglishName = null; + private String Salutation = null; + private Integer HasArrivalRecord = null; + private Integer HasDepartureRecord = null; + private Integer HasInhouseRecord = null; + private Integer HasOthersRecord = null; + private Integer HasLimoRecord = null; + private Integer HasFlightRecord = null; + private String ETA = null; + private Boolean roomReady = false; + private Boolean isQueue = false; + private Integer BigWinFlag = null; + private Integer BigLossFlag = null; + private Integer NoPlayFlag = null; + private Integer MAId = null; + private String MA = null; + private List Descriptions = null; + + public TodoListRecord() { + + } + + + + public String getDate() { + return Date; + } + + + + public void setDate(String date) { + Date = date; + } + + + + public String getActionDate() { + return ActionDate; + } + + + + public void setActionDate(String actionDate) { + ActionDate = actionDate; + } + + + + public String getOperaConfirmationNo() { + return OperaConfirmationNo; + } + + + + public void setOperaConfirmationNo(String operaConfirmationNo) { + OperaConfirmationNo = operaConfirmationNo; + } + + + + public Integer getPlayerId() { + return PlayerId; + } + + public void setPlayerId(Integer playerId) { + PlayerId = playerId; + } + + public String getTierName() { + return TierName; + } + + public void setTierName(String tierName) { + TierName = tierName; + } + + public String getChineseName() { + return ChineseName; + } + + public void setChineseName(String chineseName) { + ChineseName = chineseName; + } + + public String getEnglishName() { + return EnglishName; + } + + public void setEnglishName(String englishName) { + EnglishName = englishName; + } + + public String getSalutation() { + return Salutation; + } + + public void setSalutation(String salutation) { + Salutation = salutation; + } + + public Integer getHasArrivalRecord() { + return HasArrivalRecord; + } + + public void setHasArrivalRecord(Integer hasArrivalRecord) { + HasArrivalRecord = hasArrivalRecord; + } + + public Integer getHasDepartureRecord() { + return HasDepartureRecord; + } + + public void setHasDepartureRecord(Integer hasDepartureRecord) { + HasDepartureRecord = hasDepartureRecord; + } + + public Integer getHasInhouseRecord() { + return HasInhouseRecord; + } + + public void setHasInhouseRecord(Integer hasInhouseRecord) { + HasInhouseRecord = hasInhouseRecord; + } + + public Integer getHasOthersRecord() { + return HasOthersRecord; + } + + public void setHasOthersRecord(Integer hasOthersRecord) { + HasOthersRecord = hasOthersRecord; + } + + public Integer getHasLimoRecord() { + return HasLimoRecord; + } + + public void setHasLimoRecord(Integer hasLimoRecord) { + HasLimoRecord = hasLimoRecord; + } + + public Integer getHasFlightRecord() { + return HasFlightRecord; + } + + public void setHasFlightRecord(Integer hasFlightRecord) { + HasFlightRecord = hasFlightRecord; + } + + public String getETA() { + return ETA; + } + + public void setETA(String eTA) { + ETA = eTA; + } + + public Boolean getRoomReady() { + return roomReady; + } + + public void setRoomReady(Boolean roomReady) { + this.roomReady = roomReady; + } + + public Boolean getIsQueue() { + return isQueue; + } + + public void setIsQueue(Boolean isQueue) { + this.isQueue = isQueue; + } + + public Integer getBigWinFlag() { + return BigWinFlag; + } + + public void setBigWinFlag(Integer bigWinFlag) { + BigWinFlag = bigWinFlag; + } + + public Integer getBigLossFlag() { + return BigLossFlag; + } + + public void setBigLossFlag(Integer bigLossFlag) { + BigLossFlag = bigLossFlag; + } + + public Integer getNoPlayFlag() { + return NoPlayFlag; + } + + public void setNoPlayFlag(Integer noPlayFlag) { + NoPlayFlag = noPlayFlag; + } + + public Integer getMAId() { + return MAId; + } + + public void setMAId(Integer mAId) { + MAId = mAId; + } + + public String getMA() { + return MA; + } + + public void setMA(String mA) { + MA = mA; + } + + public List getDescriptions() { + return Descriptions; + } + + public void setDescriptions(List descriptions) { + Descriptions = descriptions; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoListResult.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoListResult.java new file mode 100644 index 0000000..ea8a4e6 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/TodoListResult.java @@ -0,0 +1,43 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import java.util.ArrayList; +import java.util.List; + + +public class TodoListResult { + + + private String statusCode = null; + private String statusDescription=null; + private List Records = new ArrayList(); + + public TodoListResult() { + + } + + 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 List getRecords() { + return Records; + } + + public void setRecords(List records) { + Records = records; + } + + +} 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 new file mode 100644 index 0000000..309eab4 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/UserInfoApiRecord.java @@ -0,0 +1,37 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + + +import lombok.Data; + +@Data +public class UserInfoApiRecord { + + private String statusCode = null; + private String statusDescription=""; + private String userId; + private String userName; + private String property; + private String division; + private String department; + private String section; + private String block; + private Long propertyId; + private Long divisionId; + private Long departmentId; + private Long sectionId; + private Long blockId; + private Long teamStructureId; + private boolean canViewBooking=false; + private boolean canNewBooking=false; + private boolean canViewTodoList=false; + private boolean canViewDashboard=false; + private boolean canViewApproval=false; + private String groupName; + private String phone; + private boolean loginTag; + + public UserInfoApiRecord() { + + } + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/UserInfoApiResult.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/UserInfoApiResult.java new file mode 100644 index 0000000..440d5fb --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/UserInfoApiResult.java @@ -0,0 +1,31 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import java.util.List; + + +public class UserInfoApiResult { + + private String statusCode; + private String statusDescription; + private List records; + 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 List getRecords() { + return records; + } + public void setRecords(List records) { + this.records = records; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/WaitlistBookingApiResult.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/WaitlistBookingApiResult.java new file mode 100644 index 0000000..82e437f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/WaitlistBookingApiResult.java @@ -0,0 +1,33 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import java.util.List; + +public class WaitlistBookingApiResult { + + private String statusCode; + private String statusDescription; + private List records; + 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 List getRecords() { + return records; + } + public void setRecords(List records) { + this.records = records; + } + + + + + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/WaitlistBookingRecord.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/WaitlistBookingRecord.java new file mode 100644 index 0000000..64c4639 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/WaitlistBookingRecord.java @@ -0,0 +1,29 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +public class WaitlistBookingRecord { + + private String playerId; + private String bookingId; + private String bookingStatus; + + public String getPlayerId() { + return playerId; + } + public void setPlayerId(String playerId) { + this.playerId = playerId; + } + public String getBookingId() { + return bookingId; + } + public void setBookingId(String bookingId) { + this.bookingId = bookingId; + } + public String getBookingStatus() { + return bookingStatus; + } + public void setBookingStatus(String bookingStatus) { + this.bookingStatus = bookingStatus; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/WaitlistDataApiResult.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/WaitlistDataApiResult.java new file mode 100644 index 0000000..3d81357 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/WaitlistDataApiResult.java @@ -0,0 +1,33 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +import java.util.List; + +public class WaitlistDataApiResult { + + private String statusCode; + private String statusDescription; + private List records; + 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 List getRecords() { + return records; + } + public void setRecords(List records) { + this.records = records; + } + + + + + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/WaitlistDataRecord.java b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/WaitlistDataRecord.java new file mode 100644 index 0000000..cdaa732 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/mgm_api/WaitlistDataRecord.java @@ -0,0 +1,153 @@ +package com.mgm.mcrm.common.dtos.mgm_api; + +public class WaitlistDataRecord { + + private String bookingId; + private String playerId; + private String overlapBooking; + private String mABooking; + private String r3TheoWin; + private String r3TPD; + private String r3ActualWin; + private String r6TheoWin; + private String r6TPD; + private String r6ActualWin; + private String r12TheoWin; + private String r12TPD; + private String r12ActualWin; + private String finalSegment; + private String tripTheoProfit; + private String dailyTheoProfit; + private String playerType; + private String rankingByPlayer; + private String bookerTeam; + private String currentTripTheoWinAmount; + private String last2DayTheoWinAmount; + public String getBookingId() { + return bookingId; + } + public void setBookingId(String bookingId) { + this.bookingId = bookingId; + } + public String getPlayerId() { + return playerId; + } + public void setPlayerId(String playerId) { + this.playerId = playerId; + } + public String getOverlapBooking() { + return overlapBooking; + } + public void setOverlapBooking(String overlapBooking) { + this.overlapBooking = overlapBooking; + } + public String getmABooking() { + return mABooking; + } + public void setmABooking(String mABooking) { + this.mABooking = mABooking; + } + public String getR3TheoWin() { + return r3TheoWin; + } + public void setR3TheoWin(String r3TheoWin) { + this.r3TheoWin = r3TheoWin; + } + public String getR3TPD() { + return r3TPD; + } + public void setR3TPD(String r3tpd) { + r3TPD = r3tpd; + } + public String getR3ActualWin() { + return r3ActualWin; + } + public void setR3ActualWin(String r3ActualWin) { + this.r3ActualWin = r3ActualWin; + } + public String getR6TheoWin() { + return r6TheoWin; + } + public void setR6TheoWin(String r6TheoWin) { + this.r6TheoWin = r6TheoWin; + } + public String getR6TPD() { + return r6TPD; + } + public void setR6TPD(String r6tpd) { + r6TPD = r6tpd; + } + public String getR6ActualWin() { + return r6ActualWin; + } + public void setR6ActualWin(String r6ActualWin) { + this.r6ActualWin = r6ActualWin; + } + public String getR12TheoWin() { + return r12TheoWin; + } + public void setR12TheoWin(String r12TheoWin) { + this.r12TheoWin = r12TheoWin; + } + public String getR12TPD() { + return r12TPD; + } + public void setR12TPD(String r12tpd) { + r12TPD = r12tpd; + } + public String getR12ActualWin() { + return r12ActualWin; + } + public void setR12ActualWin(String r12ActualWin) { + this.r12ActualWin = r12ActualWin; + } + public String getFinalSegment() { + return finalSegment; + } + public void setFinalSegment(String finalSegment) { + this.finalSegment = finalSegment; + } + public String getTripTheoProfit() { + return tripTheoProfit; + } + public void setTripTheoProfit(String tripTheoProfit) { + this.tripTheoProfit = tripTheoProfit; + } + public String getDailyTheoProfit() { + return dailyTheoProfit; + } + public void setDailyTheoProfit(String dailyTheoProfit) { + this.dailyTheoProfit = dailyTheoProfit; + } + public String getPlayerType() { + return playerType; + } + public void setPlayerType(String playerType) { + this.playerType = playerType; + } + public String getRankingByPlayer() { + return rankingByPlayer; + } + public void setRankingByPlayer(String rankingByPlayer) { + this.rankingByPlayer = rankingByPlayer; + } + public String getBookerTeam() { + return bookerTeam; + } + public void setBookerTeam(String bookerTeam) { + this.bookerTeam = bookerTeam; + } + public String getCurrentTripTheoWinAmount() { + return currentTripTheoWinAmount; + } + public void setCurrentTripTheoWinAmount(String currentTripTheoWinAmount) { + this.currentTripTheoWinAmount = currentTripTheoWinAmount; + } + public String getLast2DayTheoWinAmount() { + return last2DayTheoWinAmount; + } + public void setLast2DayTheoWinAmount(String last2DayTheoWinAmount) { + this.last2DayTheoWinAmount = last2DayTheoWinAmount; + } + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/msg/AppSettingMsgData.java b/src/main/java/com/mgm/mcrm/common/dtos/msg/AppSettingMsgData.java new file mode 100644 index 0000000..e33bcb5 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/msg/AppSettingMsgData.java @@ -0,0 +1,20 @@ +package com.mgm.mcrm.common.dtos.msg; + +import java.util.List; + +public class AppSettingMsgData { + private String serverType; + private List configItems; + public String getServerType() { + return serverType; + } + public void setServerType(String serverType) { + this.serverType = serverType; + } + public List getConfigItems() { + return configItems; + } + public void setConfigItems(List configItems) { + this.configItems = configItems; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/msg/JMSTextMessage.java b/src/main/java/com/mgm/mcrm/common/dtos/msg/JMSTextMessage.java new file mode 100644 index 0000000..ac98a05 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/msg/JMSTextMessage.java @@ -0,0 +1,27 @@ +package com.mgm.mcrm.common.dtos.msg; + +import java.util.Date; + +public class JMSTextMessage { + private String msgType; + private Date sendTime = new Date(); + private String msgContent; + public String getMsgType() { + return msgType; + } + public void setMsgType(String msgType) { + this.msgType = msgType; + } + public Date getSendTime() { + return sendTime; + } + public void setSendTime(Date sendTime) { + this.sendTime = sendTime; + } + public String getMsgContent() { + return msgContent; + } + public void setMsgContent(String msgContent) { + this.msgContent = msgContent; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/msg/UpdateCfgItem.java b/src/main/java/com/mgm/mcrm/common/dtos/msg/UpdateCfgItem.java new file mode 100644 index 0000000..a64c98e --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/msg/UpdateCfgItem.java @@ -0,0 +1,18 @@ +package com.mgm.mcrm.common.dtos.msg; + +public class UpdateCfgItem { + private String cfgItemKey; + private String cfgItemValue; + public String getCfgItemKey() { + return cfgItemKey; + } + public void setCfgItemKey(String cfgItemKey) { + this.cfgItemKey = cfgItemKey; + } + public String getCfgItemValue() { + return cfgItemValue; + } + public void setCfgItemValue(String cfgItemValue) { + this.cfgItemValue = cfgItemValue; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/system/AppServerState.java b/src/main/java/com/mgm/mcrm/common/dtos/system/AppServerState.java new file mode 100644 index 0000000..5832e3e --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/system/AppServerState.java @@ -0,0 +1,56 @@ +package com.mgm.mcrm.common.dtos.system; + +import java.util.Date; + +public class AppServerState { + + private String serverIp=""; + private String hostName=""; + private String serverType=""; + private boolean dbDebugLog=false; + private boolean apiDebugLog=false; + private boolean appDebugLog=false; + private Date lastUpdateTime=new Date(); + public String getServerIp() { + return serverIp; + } + public void setServerIp(String serverIp) { + this.serverIp = serverIp; + } + public String getHostName() { + return hostName; + } + public void setHostName(String hostName) { + this.hostName = hostName; + } + public boolean isDbDebugLog() { + return dbDebugLog; + } + public void setDbDebugLog(boolean dbDebugLog) { + this.dbDebugLog = dbDebugLog; + } + public boolean isApiDebugLog() { + return apiDebugLog; + } + public void setApiDebugLog(boolean apiDebugLog) { + this.apiDebugLog = apiDebugLog; + } + public boolean isAppDebugLog() { + return appDebugLog; + } + public void setAppDebugLog(boolean appDebugLog) { + this.appDebugLog = appDebugLog; + } + public Date getLastUpdateTime() { + return lastUpdateTime; + } + public void setLastUpdateTime(Date lastUpdateTime) { + this.lastUpdateTime = lastUpdateTime; + } + public String getServerType() { + return serverType; + } + public void setServerType(String serverType) { + this.serverType = serverType; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/system/ResFileResult.java b/src/main/java/com/mgm/mcrm/common/dtos/system/ResFileResult.java new file mode 100644 index 0000000..8660671 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/system/ResFileResult.java @@ -0,0 +1,34 @@ +package com.mgm.mcrm.common.dtos.system; + +public class ResFileResult { + private boolean success=false; + private String fileName; + private String filePath; + private String errorMessage; + public boolean isSuccess() { + return success; + } + public void setSuccess(boolean success) { + this.success = success; + } + public String getFileName() { + return fileName; + } + public void setFileName(String fileName) { + this.fileName = fileName; + } + public String getFilePath() { + return filePath; + } + public void setFilePath(String filePath) { + this.filePath = filePath; + } + public String getErrorMessage() { + return errorMessage; + } + public void setMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/common/dtos/system/RouterPages.java b/src/main/java/com/mgm/mcrm/common/dtos/system/RouterPages.java new file mode 100644 index 0000000..18e81e5 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/dtos/system/RouterPages.java @@ -0,0 +1,22 @@ +package com.mgm.mcrm.common.dtos.system; + +import com.mgm.mcrm.authorization.models.SysRouter; + +import java.io.Serializable; +import java.sql.Date; +import java.util.List; + + +public class RouterPages implements Serializable { + + private List pages; + + public List getPages() { + return pages; + } + + public void setPages(List pages) { + this.pages = pages; + } + +} diff --git a/src/main/java/com/mgm/mcrm/common/enums/DeliveryReceiptState.java b/src/main/java/com/mgm/mcrm/common/enums/DeliveryReceiptState.java new file mode 100644 index 0000000..4b7f997 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/enums/DeliveryReceiptState.java @@ -0,0 +1,56 @@ +package com.mgm.mcrm.common.enums; + +public enum DeliveryReceiptState { + + ESME_ROK(0, "Ok - Message Acceptable"), + + ESME_RINVMSGLEN(1, "Invalid Message Length"), + + ESME_RINVCMDLEN(2, "Invalid Command Length"), + + ESME_RINVCMDID(3, "Invalid Command ID"), + + ESME_RINVBNDSTS(4, "Invalid bind status"), + + ESME_RALYBND(5, "Bind attempted when already bound"), + + ESME_RINVPRTFLG(6, "Invalid priority flag"), + + ESME_RINVREGDLVFLG(7, "Invalid registered-delivery flag"), + + ESME_RSYSERR(8, "SMSC system error"), + + ESME_RINVSRCADR(9, "Invalid source address"), + + ESME_RINVDSTADR(11, "Invalid destination address"), + + ESME_RINVMSGID(12, "Invalid message-id"), + + NOT_FOUND(000, "Couldn't resolve.Ask admin to add."); + + private int value; + private String description; + + DeliveryReceiptState(int value, String description) { + this.value = value; + this.description = description; + } + + public static DeliveryReceiptState getDescription(int value) { + for (DeliveryReceiptState item : values()) { + if (item.value() == value) { + return item; + } + } + return NOT_FOUND; + } + + public int value() { + return value; + } + + public String description() { + return description; + } + +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/common/enums/EnumBookingStatus.java b/src/main/java/com/mgm/mcrm/common/enums/EnumBookingStatus.java new file mode 100644 index 0000000..14d16ae --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/enums/EnumBookingStatus.java @@ -0,0 +1,78 @@ +package com.mgm.mcrm.common.enums; + +import lombok.Getter; + +public enum EnumBookingStatus { + + DUE_IN("DUE IN", "DUE_IN"), + DUE_IN_UNDERSCORE("DUE_IN", "DUE_IN"), + DUEIN("DUEIN", "DUE_IN"), + RESERVED("RESERVED", "RESERVED"), + RESERVE("Reserved", "RESERVED"), + CHECKEDIN("Checked in", "CHECKED_IN"), + CHECKED_IN("CHECKED IN", "CHECKED_IN"), + CHECKED_IN_UNDERSCORE("CHECKED_IN", "CHECKED_IN"), + CHECK_IN("CHECK_IN", "CHECKED_IN"), + CHECK_IN_IN_HOUSE("CHECK_IN(IN_HOUSE)", "CHECKED_IN"), + CHECKED_OUT("CHECKED OUT", "CHECKED_OUT"), + CHECKED_OUT_UNDERSCORE("CHECKED_OUT", "CHECKED_OUT"), + INHOUSE("INHOUSE", "CHECKED_IN"), + IN_HOUSE("IN-HOUSE", "CHECKED_IN"), + IN_HOUSE_UNDERSCORE("IN_HOUSE", "CHECKED_IN"), + IN("IN", "CHECKED_IN"), + IH("IH", "CHECKED_IN"), + DUE_OUT("DUE OUT", "DUE_OUT"), + DUE_OUT_UNDERSCORE("DUE_OUT", "DUE_OUT"), + DUEOUT("DUEOUT", "DUE_OUT"), + CANCELED("CANCELED", "CANCELED"), + CANCELLED("CANCELLED", "CANCELED"); + + @Getter + private final String key; + @Getter + private final String value; + + EnumBookingStatus(String key, String value) { + this.key = key; + this.value = value; + } + + public static String getStatusByDaylightStatus(String key) { + if (key == null) { + return "UNKNOWN"; + } + String normalizedKey = key.trim(); + EnumBookingStatus[] objs = values(); + for (EnumBookingStatus obj : objs) { + if (obj.getKey().equalsIgnoreCase(normalizedKey)) { + return obj.getValue(); + } + } + String compactKey = normalizeStatusKey(normalizedKey); + for (EnumBookingStatus obj : objs) { + String compactObjKey = normalizeStatusKey(obj.getKey()); + if (compactObjKey.equalsIgnoreCase(compactKey)) { + return obj.getValue(); + } + } + if (compactKey.contains("CHECKIN") || compactKey.contains("INHOUSE")) { + return "CHECKED_IN"; + } + return "UNKNOWN"; + } + + private static String normalizeStatusKey(String key) { + return key == null ? "" : key.replaceAll("[^A-Za-z0-9]", ""); + } + + public static boolean isInclude(String value) { + boolean include = false; + for (EnumBookingStatus e : EnumBookingStatus.values()) { + if (e.getValue().equals(value)) { + include = true; + break; + } + } + return include; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/enums/HttpMethods.java b/src/main/java/com/mgm/mcrm/common/enums/HttpMethods.java new file mode 100644 index 0000000..b587188 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/enums/HttpMethods.java @@ -0,0 +1,74 @@ +package com.mgm.mcrm.common.enums; + + +/** + * 枚举HttpMethods方法 + * + * @author Anka + */ +public enum HttpMethods { + + /** + * 求获取Request-URI所标识的资源 + */ + GET(0, "GET"), + + /** + * 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。 + * POST请求可能会导致新的资源的建立和/或已有资源的修改 + */ + POST(1, "POST"), + + /** + * 向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。 + * 这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息 + * 只获取响应信息报头 + */ + HEAD(2, "HEAD"), + + /** + * 向指定资源位置上传其最新内容(全部更新,操作幂等) + */ + PUT (3, "PUT"), + + /** + * 请求服务器删除Request-URI所标识的资源 + */ + DELETE (4, "DELETE"), + + /** + * 请求服务器回送收到的请求信息,主要用于测试或诊断 + */ + TRACE(5, "TRACE"), + + /** + * 向指定资源位置上传其最新内容(部分更新,非幂等) + */ + PATCH (6, "PATCH"), + + /** + * 返回服务器针对特定资源所支持的HTTP请求方法。 + * 也可以利用向Web服务器发送'*'的请求来测试服务器的功能性 + */ + OPTIONS (7, "OPTIONS"), + +// /** +// * HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器 +// */ +// CONNECT(99, "CONNECT"), + ; + + private int code; + private String name; + + private HttpMethods(int code, String name){ + this.code = code; + this.name = name; + } + public String getName() { + return name; + } + public int getCode() { + return code; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/filters/ConfigHeaderFilter.java b/src/main/java/com/mgm/mcrm/common/filters/ConfigHeaderFilter.java new file mode 100644 index 0000000..531e83c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/filters/ConfigHeaderFilter.java @@ -0,0 +1,76 @@ +package com.mgm.mcrm.common.filters; + +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.utils.LogUtil; +import com.mgm.mcrm.common.utils.NetworkUtil; +import jakarta.servlet.*; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.io.IOException; + +@Slf4j +public class ConfigHeaderFilter implements Filter { + @Override + public void init(FilterConfig filterConfig) throws ServletException { + + } + + @Override + public void destroy() { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + + HttpServletRequest req = (HttpServletRequest) request; + + if (response instanceof HttpServletResponse httpServletResponse) { + String origin = ((HttpServletRequest) request).getHeader("Origin"); + if (StringUtils.isBlank(origin) && "127.0.0.1".equals(NetworkUtil.getClientIpAddr((HttpServletRequest) request))) { + httpServletResponse.setHeader("Access-Control-Allow-Origin", null); + } else { + String sanitizedOrigin = NetworkUtil.encodePathWithSpring(origin); + if (SysCommon.isAllowOriginSource(sanitizedOrigin)) { + httpServletResponse.setHeader("Access-Control-Allow-Origin", sanitizedOrigin); + } else { + LogUtil.warn(ConfigHeaderFilter.class, "Origin of [" + sanitizedOrigin + "] is not allowed"); + httpServletResponse.setHeader("Access-Control-Allow-Origin", ""); + log.warn("Blocked request: method={}, uri={}, query={}, origin={}, referer={}, ip={}, xff={}, userAgent={}", + req.getMethod(), + req.getRequestURI(), + req.getQueryString(), + req.getHeader("Origin"), + req.getHeader("Referer"), + req.getRemoteAddr(), + req.getHeader("X-Forwarded-For"), + req.getHeader("User-Agent")); + + return; + } + } + httpServletResponse.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD"); + httpServletResponse.addHeader("Access-Control-Allow-Headers", "Content-Type,Authorization,ClientId,Refreshtoken"); + httpServletResponse.addHeader("Access-Control-Allow-Credentials", "true"); + httpServletResponse.addHeader("Access-Control-Max-Age", "3600"); + httpServletResponse.addHeader("Access-Control-Expose-Headers", "MacauIP, IsInternal"); + + if (request.isSecure()) { + httpServletResponse.setHeader("Strict-Transport-Security", + "max-age=86400; includeSubDomains; preload"); + } + httpServletResponse.setHeader("X-Frame-Options", "SAMEORIGIN"); + httpServletResponse.setHeader("X-Content-Type-Options", "nosniff"); + httpServletResponse.setHeader("Content-Security-Policy", + "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; " + + "style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; " + + "connect-src 'self'; media-src 'self'; object-src 'none'; frame-src 'self'"); + httpServletResponse.setHeader("Referrer-Policy", "strict-origin-when-cross-origin"); + httpServletResponse.setHeader("X-XSS-Protection", "1; mode=block"); + } + chain.doFilter(request, response); + } +} diff --git a/src/main/java/com/mgm/mcrm/common/httpclient/HttpClientExecutor.java b/src/main/java/com/mgm/mcrm/common/httpclient/HttpClientExecutor.java new file mode 100644 index 0000000..5e0006f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/httpclient/HttpClientExecutor.java @@ -0,0 +1,523 @@ +package com.mgm.mcrm.common.httpclient; + +import com.mgm.mcrm.common.dtos.HttpResult; +import com.mgm.mcrm.common.enums.HttpMethods; +import org.apache.hc.client5.http.classic.methods.HttpDelete; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.classic.methods.HttpPatch; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.classic.methods.HttpPut; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.core5.http.ClassicHttpRequest; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.http.io.entity.EntityUtils; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * HTTP 客户端工具类(基于 Apache HttpClient 5) + * + * 提供便捷的 HTTP 请求方法,支持: + * - GET、POST、PUT、DELETE 请求 + * - 自定义请求头和参数 + * - Cookie 管理 + * - 详细响应信息获取 + * + * 使用示例: + *
+ * // 配置请求
+ * HttpConfig config = HttpConfig.custom()
+ *     .url("https://api.example.com/data")
+ *     .timeout(requestConfig)
+ *     .map(params)
+ *     .encoding("utf-8")
+ *     .client(httpClient);
+ *
+ * // 配置请求头
+ * Header[] headers = HttpHeaderUtil.custom()
+ *     .userAgent("MyApp")
+ *     .build();
+ *
+ * // 执行 GET 请求
+ * String result = HttpClientUtil.get(config, headers);
+ *
+ * // 执行 POST 请求
+ * String result = HttpClientUtil.post(config, headers);
+ *
+ * // 获取详细响应信息
+ * HttpResult httpResult = HttpClientUtil.sendAndGetResp(config, headers);
+ * 
+ * + * @author Aaka + */ +public class HttpClientExecutor { + + private HttpClientExecutor() { + // 工具类,禁止实例化 + } + + /** + * 执行 GET 请求 + * + * @param config HTTP 请求配置 + * @param headers 请求头数组(可选,可为 null) + * @return 响应体字符串 + * @throws Exception 请求执行异常 + */ + public static String get(HttpRequestOptions config, Header[] headers) throws Exception { + return executeGet(config, headers); + } + + /** + * 执行 POST 请求 + * + * @param config HTTP 请求配置 + * @param headers 请求头数组(可选,可为 null) + * @return 响应体字符串 + * @throws Exception 请求执行异常 + */ + public static String post(HttpRequestOptions config, Header[] headers) throws Exception { + return executePost(config, headers); + } + + /** + * 执行通用请求(根据 HttpConfig 中的 method 自动选择) + * + * @param config HTTP 请求配置 + * @param headers 请求头数组(可选,可为 null) + * @return 响应体字符串 + * @throws Exception 请求执行异常 + */ + public static String send(HttpRequestOptions config, Header[] headers) throws Exception { + return execute(config, headers); + } + + /** + * 执行请求并返回详细响应信息 + * + * @param config HTTP 请求配置 + * @param headers 请求头数组(可选,可为 null) + * @return HttpResult 包含完整的响应信息(状态码、响应头、响应体等) + * @throws Exception 请求执行异常 + */ + public static HttpResult sendAndGetResp(HttpRequestOptions config, Header[] headers) throws Exception { + return executeAndGetResp(config, headers); + } + + /** + * 执行请求并返回详细响应信息 + * + * @param config HTTP 请求配置 + * @param headers 请求头数组(可选,可为 null) + * @return HttpResult 包含完整的响应信息(状态码、响应头、响应体等) + * @throws Exception 请求执行异常 + */ + public static HttpResult sendAndPostResp(HttpRequestOptions config, Header[] headers) throws Exception { + return executePostRes(config, headers); + } + + /** + * 执行 PATCH 请求并返回详细响应信息 + * + * @param config HTTP 请求配置 + * @param headers 请求头数组(可选,可为 null) + * @return HttpResult 包含完整的响应信息(状态码、响应头、响应体等) + * @throws Exception 请求执行异常 + */ + public static HttpResult sendAndPatchResp(HttpRequestOptions config, Header[] headers) throws Exception { + return executePatchRes(config, headers); + } + + /** + * 执行 GET 请求(内部方法) + */ + private static String executeGet(HttpRequestOptions config, Header[] headers) throws Exception { + String url = config.url(); + List nvps = new ArrayList<>(); + // 1. 先解析 URL 中原本就带的查询参数(如果有) + // 2. 再把 HttpConfig.map() 里的参数也加入到 nvps 中 + // 对于 GET 请求,这些参数应该拼到 URL 上,而不是放到 body 里 + Map map = config.map(); + if (map != null && !map.isEmpty()) { + url = HttpEntityBuilder.checkHasParas(url, nvps, config.inenc()); + // 这里主要是为了复用参数编码逻辑,返回的 entity 我们不用 + HttpEntityBuilder.map2HttpEntity(nvps, map, config.inenc()); + } + + // 3. 如果 nvps 中有参数,手动构建查询字符串 + // 注意:某些服务器(如接口测试工具)可能期望参数值中的特殊字符(如 == 和 ;)不被编码 + // 因此我们只对参数名进行编码,参数值保持原样或只编码必要的字符 + if (!nvps.isEmpty()) { + StringBuilder queryBuilder = new StringBuilder(); + for (int i = 0; i < nvps.size(); i++) { + NameValuePair nvp = nvps.get(i); + if (i > 0) { + queryBuilder.append("&"); + } + try { + // 只对参数名进行编码 + String encodedName = encodeQueryParam(nvp.getName(), config.inenc()); + // 参数值保持原样,不进行编码(与接口测试工具行为一致) + // 如果参数值中包含需要编码的字符(如中文、空格等),可以在这里添加编码逻辑 + String paramValue = nvp.getValue(); + queryBuilder.append(encodedName).append("=").append(paramValue); + } catch (Exception ex) { + // 如果编码失败,使用原始值 + queryBuilder.append(nvp.getName()).append("=").append(nvp.getValue()); + } + } + String query = queryBuilder.toString(); + if (url.contains("?")) { + url = url + "&" + query; + } else { + url = url + "?" + query; + } + } +// System.out.println(url); + HttpGet httpGet = new HttpGet(url); + setHeaders(httpGet, headers); + setRequestConfig(httpGet, config); + + // 如果配置了 context,使用 context 执行请求以支持 Cookie + // 注意:execute 方法在 HttpClient 5 中被标记为 deprecated,但这是目前推荐的方式 + CloseableHttpResponse response; + if (config.context() != null) { + @SuppressWarnings("deprecation") + CloseableHttpResponse tempResponse = (CloseableHttpResponse) config.client().execute(httpGet, config.context()); + response = tempResponse; + } else { + @SuppressWarnings("deprecation") + CloseableHttpResponse tempResponse = (CloseableHttpResponse) config.client().execute(httpGet); + response = tempResponse; + } + try (response) { + return extractResponseBody(response, config); + } + } + + /** + * 执行 POST 请求(内部方法) + */ + private static String executePost(HttpRequestOptions config, Header[] headers) throws Exception { + String url = config.url(); + List nvps = new ArrayList<>(); + url = HttpEntityBuilder.checkHasParas(url, nvps, config.inenc()); + + HttpPost httpPost = new HttpPost(url); + setHeaders(httpPost, headers); + setRequestConfig(httpPost, config); + + // 设置请求体 + Map map = config.map(); + if (map != null && !map.isEmpty()) { + HttpEntity entity = HttpEntityBuilder.map2HttpEntity(nvps, map, config.inenc()); + httpPost.setEntity(entity); + } + + // 如果配置了 context,使用 context 执行请求以支持 Cookie + // 注意:execute 方法在 HttpClient 5 中被标记为 deprecated,但这是目前推荐的方式 + CloseableHttpResponse response; + if (config.context() != null) { + @SuppressWarnings("deprecation") + CloseableHttpResponse tempResponse = (CloseableHttpResponse) config.client().execute(httpPost, config.context()); + response = tempResponse; + } else { + @SuppressWarnings("deprecation") + CloseableHttpResponse tempResponse = (CloseableHttpResponse) config.client().execute(httpPost); + response = tempResponse; + } + try (response) { + return extractResponseBody(response, config); + } + } + + /** + * 执行 POST 请求(内部方法) + */ + private static HttpResult executePostRes(HttpRequestOptions config, Header[] headers) throws Exception { + String url = config.url(); + List nvps = new ArrayList<>(); + url = HttpEntityBuilder.checkHasParas(url, nvps, config.inenc()); + + HttpPost httpPost = new HttpPost(url); + setHeaders(httpPost, headers); + setRequestConfig(httpPost, config); + + // 设置请求体 + Map map = config.map(); + if (map != null && !map.isEmpty()) { + HttpEntity entity = HttpEntityBuilder.map2HttpEntity(nvps, map, config.inenc()); + httpPost.setEntity(entity); + } + + // 如果配置了 context,使用 context 执行请求以支持 Cookie + // 注意:execute 方法在 HttpClient 5 中被标记为 deprecated,但这是目前推荐的方式 + CloseableHttpResponse response; + if (config.context() != null) { + @SuppressWarnings("deprecation") + CloseableHttpResponse tempResponse = (CloseableHttpResponse) config.client().execute(httpPost, config.context()); + response = tempResponse; + } else { + @SuppressWarnings("deprecation") + CloseableHttpResponse tempResponse = (CloseableHttpResponse) config.client().execute(httpPost); + response = tempResponse; + } + try (response) { + return buildHttpResult(response, config); + } + } + + /** + * 执行 PATCH 请求(内部方法) + */ + private static HttpResult executePatchRes(HttpRequestOptions config, Header[] headers) throws Exception { + String url = config.url(); + List nvps = new ArrayList<>(); + url = HttpEntityBuilder.checkHasParas(url, nvps, config.inenc()); + + HttpPatch httpPatch = new HttpPatch(url); + setHeaders(httpPatch, headers); + setRequestConfig(httpPatch, config); + + // 设置请求体 + Map map = config.map(); + if (map != null && !map.isEmpty()) { + HttpEntity entity = HttpEntityBuilder.map2HttpEntity(nvps, map, config.inenc()); + httpPatch.setEntity(entity); + } + + // 如果配置了 context,使用 context 执行请求以支持 Cookie + // 注意:execute 方法在 HttpClient 5 中被标记为 deprecated,但这是目前推荐的方式 + CloseableHttpResponse response; + if (config.context() != null) { + @SuppressWarnings("deprecation") + CloseableHttpResponse tempResponse = (CloseableHttpResponse) config.client().execute(httpPatch, config.context()); + response = tempResponse; + } else { + @SuppressWarnings("deprecation") + CloseableHttpResponse tempResponse = (CloseableHttpResponse) config.client().execute(httpPatch); + response = tempResponse; + } + try (response) { + return buildHttpResult(response, config); + } + } + + /** + * 执行通用请求(根据 HttpMethods 自动选择)(内部方法) + */ + private static String execute(HttpRequestOptions config, Header[] headers) throws Exception { + HttpMethods method = config.method(); + String url = config.url(); + List nvps = new ArrayList<>(); + url = HttpEntityBuilder.checkHasParas(url, nvps, config.inenc()); + + ClassicHttpRequest request = createRequest(method, url); + setHeaders(request, headers); + setRequestConfig(request, config); + + // 设置请求体(仅 POST 和 PUT) + Map map = config.map(); + if (map != null && !map.isEmpty() && (request instanceof HttpPost || request instanceof HttpPut)) { + HttpEntity entity = HttpEntityBuilder.map2HttpEntity(nvps, map, config.inenc()); + if (request instanceof HttpPost) { + ((HttpPost) request).setEntity(entity); + } else if (request instanceof HttpPut) { + ((HttpPut) request).setEntity(entity); + } + } + + // 如果配置了 context,使用 context 执行请求以支持 Cookie + // 注意:execute 方法在 HttpClient 5 中被标记为 deprecated,但这是目前推荐的方式 + CloseableHttpResponse response; + if (config.context() != null) { + @SuppressWarnings("deprecation") + CloseableHttpResponse tempResponse = (CloseableHttpResponse) config.client().execute(request, config.context()); + response = tempResponse; + } else { + @SuppressWarnings("deprecation") + CloseableHttpResponse tempResponse = (CloseableHttpResponse) config.client().execute(request); + response = tempResponse; + } + try (response) { + return extractResponseBody(response, config); + } + } + + /** + * 执行请求并返回详细响应信息(内部方法) + */ + private static HttpResult executeAndGetResp(HttpRequestOptions config, Header[] headers) throws Exception { + String url = config.url(); + List nvps = new ArrayList<>(); + // 1. 先解析 URL 中原本就带的查询参数(如果有) + url = HttpEntityBuilder.checkHasParas(url, nvps, config.inenc()); + + // 2. 再把 HttpConfig.map() 里的参数也加入到 nvps 中 + // 对于 GET 请求,这些参数应该拼到 URL 上,而不是放到 body 里 + Map map = config.map(); + if (map != null && !map.isEmpty()) { + // 这里主要是为了复用参数编码逻辑,返回的 entity 我们不用 + HttpEntityBuilder.map2HttpEntity(nvps, map, config.inenc()); + } + + // 3. 如果 nvps 中有参数,手动构建查询字符串 + // 注意:某些服务器(如接口测试工具)可能期望参数值中的特殊字符(如 == 和 ;)不被编码 + // 因此我们只对参数名进行编码,参数值保持原样或只编码必要的字符 + if (!nvps.isEmpty()) { + StringBuilder queryBuilder = new StringBuilder(); + for (int i = 0; i < nvps.size(); i++) { + NameValuePair nvp = nvps.get(i); + if (i > 0) { + queryBuilder.append("&"); + } + try { + // 只对参数名进行编码 + String encodedName = encodeQueryParam(nvp.getName(), config.inenc()); + // 参数值保持原样,不进行编码(与接口测试工具行为一致) + // 如果参数值中包含需要编码的字符(如中文、空格等),可以在这里添加编码逻辑 + String paramValue = nvp.getValue(); + queryBuilder.append(encodedName).append("=").append(paramValue); + } catch (Exception ex) { + // 如果编码失败,使用原始值 + queryBuilder.append(nvp.getName()).append("=").append(nvp.getValue()); + } + } + String query = queryBuilder.toString(); + if (url.contains("?")) { + url = url + "&" + query; + } else { + url = url + "?" + query; + } + } +// System.out.println(url); + HttpGet httpGet = new HttpGet(url); + setHeaders(httpGet, headers); + setRequestConfig(httpGet, config); + + // 如果配置了 context,使用 context 执行请求以支持 Cookie + // 注意:execute 方法在 HttpClient 5 中被标记为 deprecated,但这是目前推荐的方式 + CloseableHttpResponse response; + if (config.context() != null) { + @SuppressWarnings("deprecation") + CloseableHttpResponse tempResponse = (CloseableHttpResponse) config.client().execute(httpGet, config.context()); + response = tempResponse; + } else { + @SuppressWarnings("deprecation") + CloseableHttpResponse tempResponse = (CloseableHttpResponse) config.client().execute(httpGet); + response = tempResponse; + } + try (response) { + return buildHttpResult(response, config); + } + } + + /** + * 创建 HTTP 请求对象 + */ + private static ClassicHttpRequest createRequest(HttpMethods method, String url) { + switch (method) { + case GET: + return new HttpGet(url); + case POST: + return new HttpPost(url); + case PUT: + return new HttpPut(url); + case DELETE: + return new HttpDelete(url); + default: + return new HttpGet(url); + } + } + + /** + * 设置请求头 + */ + private static void setHeaders(ClassicHttpRequest request, Header[] headers) { + if (headers != null) { + for (Header header : headers) { + request.addHeader(header.getName(), header.getValue()); + } + } + } + + /** + * 设置请求配置 + */ + private static void setRequestConfig(ClassicHttpRequest request, HttpRequestOptions config) { + if (config.requestConfig() == null) { + return; + } + + if (request instanceof HttpGet) { + ((HttpGet) request).setConfig(config.requestConfig()); + } else if (request instanceof HttpPost) { + ((HttpPost) request).setConfig(config.requestConfig()); + } else if (request instanceof HttpPut) { + ((HttpPut) request).setConfig(config.requestConfig()); + } else if (request instanceof HttpPatch) { + ((HttpPatch) request).setConfig(config.requestConfig()); + } else if (request instanceof HttpDelete) { + ((HttpDelete) request).setConfig(config.requestConfig()); + } + } + + /** + * 提取响应体内容 + */ + private static String extractResponseBody(CloseableHttpResponse response, HttpRequestOptions config) throws Exception { + HttpEntity entity = response.getEntity(); + if (entity == null) { + return ""; + } + try { + String result = EntityUtils.toString(entity, Charset.forName(config.outenc())); + return result; + } finally { + EntityUtils.consume(entity); + } + } + + /** + * 构建 HttpResult 对象 + */ + private static HttpResult buildHttpResult(CloseableHttpResponse response, HttpRequestOptions config) throws Exception { + // 直接使用 HttpResult 构造函数,自动设置状态行、响应头、协议版本和状态码 + HttpResult result = new HttpResult(response); + + // 读取响应体内容 + HttpEntity entity = response.getEntity(); + if (entity != null) { + String responseBody = EntityUtils.toString(entity, Charset.forName(config.outenc())); + result.setResult(responseBody); + EntityUtils.consume(entity); + } + + return result; + } + + /** + * 编码查询参数名(只编码参数名,不编码参数值) + * 这样可以保持与接口测试工具的行为一致 + * + * @param param 参数名 + * @param encoding 编码格式 + * @return 编码后的参数名 + */ + private static String encodeQueryParam(String param, String encoding) { + if (param == null) { + return ""; + } + try { + // 只对参数名进行标准 URL 编码 + return java.net.URLEncoder.encode(param, encoding).replace("+", "%20"); + } catch (java.io.UnsupportedEncodingException e) { + return param; + } + } +} diff --git a/src/main/java/com/mgm/mcrm/common/httpclient/HttpCookieContext.java b/src/main/java/com/mgm/mcrm/common/httpclient/HttpCookieContext.java new file mode 100644 index 0000000..4328daa --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/httpclient/HttpCookieContext.java @@ -0,0 +1,46 @@ +package com.mgm.mcrm.common.httpclient; + +import org.apache.hc.client5.http.cookie.BasicCookieStore; +import org.apache.hc.client5.http.cookie.CookieStore; +import org.apache.hc.client5.http.protocol.HttpClientContext; + +public class HttpCookieContext { + /** + * 使用httpcontext,用于设置和携带Cookie + */ + private HttpClientContext context ; + + /** + * 储存Cookie + */ + private CookieStore cookieStore; + + public static HttpCookieContext custom(){ + return new HttpCookieContext(); + } + + private HttpCookieContext(){ + this.context = new HttpClientContext(); + this.cookieStore = new BasicCookieStore(); + this.context.setCookieStore(cookieStore); + } + + public HttpClientContext getContext() { + return context; + } + + public HttpCookieContext setContext(HttpClientContext context) { + this.context = context; + return this; + } + + public CookieStore getCookieStore() { + return cookieStore; + } + + public HttpCookieContext setCookieStore(CookieStore cookieStore) { + this.cookieStore = cookieStore; + return this; + } + +} diff --git a/src/main/java/com/mgm/mcrm/common/httpclient/HttpEntityBuilder.java b/src/main/java/com/mgm/mcrm/common/httpclient/HttpEntityBuilder.java new file mode 100644 index 0000000..53a658d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/httpclient/HttpEntityBuilder.java @@ -0,0 +1,310 @@ +package com.mgm.mcrm.common.httpclient; + +import org.apache.hc.client5.http.entity.UrlEncodedFormEntity; +import org.apache.hc.client5.http.entity.mime.HttpMultipartMode; +import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.http.io.entity.ByteArrayEntity; +import org.apache.hc.core5.http.io.entity.FileEntity; +import org.apache.hc.core5.http.io.entity.StringEntity; +import org.apache.hc.core5.http.message.BasicHeader; +import org.apache.hc.core5.http.message.BasicNameValuePair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.nio.charset.Charset; +import java.util.*; +import java.util.Map.Entry; + + +public class HttpEntityBuilder { + + //传入参数特定类型 + public static final String ENTITY_STRING="$ENTITY_STRING$"; + public static final String ENTITY_JSON="$ENTITY_JSON$"; + public static final String ENTITY_FILE="$ENTITY_FILEE$"; + public static final String ENTITY_BYTES="$ENTITY_BYTES$"; + public static final String ENTITY_INPUTSTREAM="$ENTITY_INPUTSTREAM$"; + public static final String ENTITY_SERIALIZABLE="$ENTITY_SERIALIZABLE$"; + public static final String ENTITY_MULTIPART="$ENTITY_MULTIPART$"; + private static final List SPECIAL_ENTITIY = Arrays.asList(ENTITY_STRING, ENTITY_JSON, ENTITY_BYTES, ENTITY_FILE, ENTITY_INPUTSTREAM, ENTITY_SERIALIZABLE, ENTITY_MULTIPART); + + /** + * 是否开启debug, + */ + private static boolean debug = false; + + private static final Logger log = LoggerFactory.getLogger(HttpEntityBuilder.class); + + + /** + * 检测url是否含有参数,如果有,则把参数加到参数列表中 + * + * @param url 资源地址 + * @param nvps 参数列表 + * @param encoding 编码 + * @return 返回去掉参数的url + * @throws UnsupportedEncodingException 不支持的编码异常 + */ + public static String checkHasParas(String url, List nvps, String encoding) throws UnsupportedEncodingException { + // 检测url中是否存在参数 + if (url.contains("?") && url.indexOf("?") < url.indexOf("=")) { + String[] paras = url.substring(url.indexOf("?") + 1).split("&"); + for (String para : paras) { + int pos = para.indexOf("="); + if (pos >= 0) { + nvps.add(new BasicNameValuePair(para.substring(0, pos), para.substring(pos + 1))); + } else { + nvps.add(new BasicNameValuePair(para, "")); + } + } + url = url.substring(0, url.indexOf("?")); + } + return url; + } + + /** + * + * 参数转换,将map中的参数,转到参数列表中 + * + * @param nvps 参数列表 + * @param map 参数列表(map) + * @param encoding 编码 + * @return 返回HttpEntity + * @throws UnsupportedEncodingException 不支持的编码异常 + */ + public static HttpEntity map2HttpEntity(List nvps, Map map, String encoding) throws UnsupportedEncodingException { + HttpEntity entity = null; + if(map!=null && map.size()>0){ + boolean isSpecial = false; + // 拼接参数 + for (Entry entry : map.entrySet()) { + if(SPECIAL_ENTITIY.contains(entry.getKey())){//判断是否在之中 + isSpecial = true; + if(ENTITY_STRING.equals(entry.getKey())){//string + entity = new StringEntity(String.valueOf(entry.getValue()), Charset.forName(encoding)); + break; + }else if(ENTITY_JSON.equals(entry.getKey())){//json + ContentType jsonContentType; + + entity = new StringEntity(String.valueOf(entry.getValue()), Charset.forName(encoding)); + String contentType = "application/json"; + if (encoding != null && !encoding.trim().isEmpty()) { + // 创建带有编码的JSON ContentType + jsonContentType = ContentType.APPLICATION_JSON.withCharset(Charset.forName(encoding)); + }else { + // 使用默认的JSON ContentType(通常UTF-8) + jsonContentType = ContentType.APPLICATION_JSON; + } + // 创建实体时直接传入ContentType + entity = new StringEntity(String.valueOf(entry.getValue()), jsonContentType); + break; + }else if(ENTITY_BYTES.equals(entry.getKey())){//file + byte[] data = (byte[]) entry.getValue(); + entity = new ByteArrayEntity(data, ContentType.APPLICATION_OCTET_STREAM); + break; + }else if(ENTITY_FILE.equals(entry.getKey())){//file + if(File.class.isAssignableFrom(entry.getValue().getClass())){ + entity = new FileEntity((File)entry.getValue(), ContentType.APPLICATION_OCTET_STREAM); + }else if(entry.getValue().getClass()==String.class){ + entity = new FileEntity(new File((String) entry.getValue()), ContentType.create("text/plain", "UTF-8")); + } + break; + }else if(ENTITY_INPUTSTREAM.equals(entry.getKey())){//inputstream +// entity = new InputStreamEntity(); + break; + }else if(ENTITY_SERIALIZABLE.equals(entry.getKey())){//serializeable +// entity = new SerializableEntity() + break; + }else if(ENTITY_MULTIPART.equals(entry.getKey())){//MultipartEntityBuilder + File[] files = null; + if(File.class.isAssignableFrom(entry.getValue().getClass().getComponentType())){ + files=(File[])entry.getValue(); + }else if(entry.getValue().getClass().getComponentType()==String.class){ + String[] names = (String[]) entry.getValue(); + files = new File[names.length]; + for (int i = 0; i < names.length; i++) { + files[i] = new File(names[i]); + } + } + MultipartEntityBuilder builder = MultipartEntityBuilder.create(); + builder.setCharset(Charset.forName(encoding));// 设置请求的编码格式 + builder.setMode(HttpMultipartMode.LEGACY);// 设置浏览器兼容模式 + int count = 0; + for (File file : files) { +// //把文件转换成流对象FileBody +// FileBody fileBody = new FileBody(file); +// builder.addPart(String.valueOf(map.get(ENTITY_MULTIPART+".name")) + count++, fileBody); + builder.addBinaryBody(String.valueOf(map.get(ENTITY_MULTIPART+".name")) + count++,file); + } + boolean forceRemoveContentTypeCharset = (boolean)map.get(ENTITY_MULTIPART+".rmCharset"); + Map m = new HashMap(); + m.putAll(map); + m.remove(ENTITY_MULTIPART); + m.remove(ENTITY_MULTIPART+".name"); + m.remove(ENTITY_MULTIPART+".rmCharset"); + Iterator> iterator = m.entrySet().iterator(); + // 发送的数据 + while (iterator.hasNext()) { + Entry e = iterator.next(); + builder.addTextBody(e.getKey(), String.valueOf(e.getValue()), ContentType.create("text/plain", encoding)); + } + entity = builder.build();// 生成 HTTP POST 实体 + + //强制去除contentType中的编码设置,否则,在某些情况下会导致上传失败 + if(forceRemoveContentTypeCharset){ + removeContentTypeCharset(encoding, entity); + } + break; + }else { + nvps.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue()))); + } + }else{ + nvps.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue()))); + } + } + if(!isSpecial) { + entity = new UrlEncodedFormEntity(nvps, Charset.forName(encoding)); + } + } + return entity; + } + + /** + * 移除content-type中的charset + * + * @param encoding 编码 + * @param entity 请求参数及数据信息 + */ + private static void removeContentTypeCharset(String encoding, HttpEntity entity) { + try { + Class clazz = entity.getClass(); + Field field = clazz.getDeclaredField("contentType"); + field.setAccessible(true); //将字段的访问权限设为true:即去除private修饰符的影响 + if(Modifier.isFinal(field.getModifiers())){ + Field modifiersField = Field.class.getDeclaredField("modifiers"); //去除final修饰符的影响,将字段设为可修改的 + modifiersField.setAccessible(true); + modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + } + BasicHeader o = (BasicHeader) field.get(entity); + field.set(entity, new BasicHeader(HttpHeaders.CONTENT_TYPE, o.getValue().replace("; charset="+encoding,""))); + } catch (NoSuchFieldException e) { + HttpEntityBuilder.exception(e); + } catch (SecurityException e) { + HttpEntityBuilder.exception(e); + } catch (IllegalArgumentException e) { + HttpEntityBuilder.exception(e); + } catch (IllegalAccessException e) { + HttpEntityBuilder.exception(e); + } + } + + + /** + * 生成参数 + * 参数格式:k1=v1&k2=v2 + * + * @param paras 参数列表 + * @return 返回参数列表(map) + */ + public static Map buildParas(String paras){ + String[] p = paras.split("&"); + String[][] ps = new String[p.length][2]; + int pos = 0; + for (int i = 0; i < p.length; i++) { + pos = p[i].indexOf("="); + ps[i][0]=p[i].substring(0,pos); + ps[i][1]=p[i].substring(pos+1); + pos = 0; + } + return buildParas(ps); + } + + /** + * 生成参数 + * 参数类型:{{"k1","v1"},{"k2","v2"}} + * + * @param paras 参数列表 + * @return 返回参数列表(map) + */ + public static Map buildParas(String[][] paras){ + // 创建参数队列 + Map map = new HashMap(); + for (String[] para: paras) { + map.put(para[0], para[1]); + } + return map; + } + + /** + * 打印消息 + * + * @param msg 消息 + */ + public static void info(String msg){ + if(debug){ + log.info(msg); + } + } + + /** + * 打印消息和异常堆栈 + * + * @param msg 异常消息 + * @param t 异常 + */ + public static void infoException(String msg, Throwable t){ + if(debug){ + log.info(msg,t); + } + } + + /** + * 打印错误消息 + * + * @param msg 异常消息 + */ + public static void error(String msg){ + log.error(msg); + } + + /** + * 打印错误消息和异常堆栈 + * + * @param msg 异常消息 + * @param t 异常 + */ + public static void errorException(String msg, Throwable t){ + log.error(msg, t); + } + + /** + * 打印异常堆栈 + * + * @param t 异常 + */ + public static void exception(Throwable t){ + log.error(String.valueOf(t)); + } + + /** + * 开启打印日志 + */ + public static void debug() { + debug(true); + } + /** + * 开启或关闭打印日志 + * @param debug 是否开启debug + */ + public static void debug(boolean debug) { + HttpEntityBuilder.debug = debug; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/httpclient/HttpHeaderBuilder.java b/src/main/java/com/mgm/mcrm/common/httpclient/HttpHeaderBuilder.java new file mode 100644 index 0000000..1510491 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/httpclient/HttpHeaderBuilder.java @@ -0,0 +1,697 @@ +package com.mgm.mcrm.common.httpclient; + + +import com.mgm.mcrm.common.config.HttpHeader; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.message.BasicHeader; + +import java.net.URLConnection; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + + +/** + * http 发送参数 + * + * @author Aaka + */ +public class HttpHeaderBuilder { + + private HttpHeaderBuilder() {}; + + public static HttpHeaderBuilder custom() { + return new HttpHeaderBuilder(); + } + + //记录head头信息 + private Map headerMaps = new HashMap(); + + /** + * 自定义header头信息 + * + * @param key header-key + * @param value header-value + * @return 返回当前对象 + */ + public HttpHeaderBuilder other(String key, String value) { + headerMaps.put(key, new BasicHeader(key, value)); + return this; + } + /** + * 指定客户端能够接收的内容类型 + * 例如:Accept: text/plain, text/html + * + * @param accept accept + * @return 返回当前对象 + */ + public HttpHeaderBuilder accept(String accept) { + headerMaps.put(HttpReqHead.ACCEPT, + new BasicHeader(HttpReqHead.ACCEPT, accept)); + return this; + } + + /** + * 浏览器可以接受的字符编码集 + * 例如:Accept-Charset: iso-8859-5 + * + * @param acceptCharset accept-charset + * @return 返回当前对象 + */ + public HttpHeaderBuilder acceptCharset(String acceptCharset) { + headerMaps.put(HttpReqHead.ACCEPT_CHARSET, + new BasicHeader(HttpReqHead.ACCEPT_CHARSET, acceptCharset)); + return this; + } + + /** + * 指定浏览器可以支持的web服务器返回内容压缩编码类型 + * 例如:Accept-Encoding: compress, gzip + * + * @param acceptEncoding accept-encoding + * @return 返回当前对象 + */ + public HttpHeaderBuilder acceptEncoding(String acceptEncoding) { + headerMaps.put(HttpReqHead.ACCEPT_ENCODING, + new BasicHeader(HttpReqHead.ACCEPT_ENCODING, acceptEncoding)); + return this; + } + + /** + * 浏览器可接受的语言 + * 例如:Accept-Language: en,zh + * + * @param acceptLanguage accept-language + * @return 返回当前对象 + */ + public HttpHeaderBuilder acceptLanguage(String acceptLanguage) { + headerMaps.put(HttpReqHead.ACCEPT_LANGUAGE, + new BasicHeader(HttpReqHead.ACCEPT_LANGUAGE, acceptLanguage)); + return this; + } + + /** + * 可以请求网页实体的一个或者多个子范围字段 + * 例如:Accept-Ranges: bytes + * + * @param acceptRanges accept-ranges + * @return 返回当前对象 + */ + public HttpHeaderBuilder acceptRanges(String acceptRanges) { + headerMaps.put(HttpReqHead.ACCEPT_RANGES, + new BasicHeader(HttpReqHead.ACCEPT_RANGES, acceptRanges)); + return this; + } + + /** + * HTTP授权的授权证书 + * 例如:Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== + * + * @param authorization authorization + * @return 返回当前对象 + */ + public HttpHeaderBuilder authorization(String authorization) { + headerMaps.put(HttpReqHead.AUTHORIZATION, + new BasicHeader(HttpReqHead.AUTHORIZATION, authorization)); + return this; + } + + public HttpHeaderBuilder ac_property_id(String ac_property_id) { + headerMaps.put(HttpReqHead.AC_PROPERTY_ID, + new BasicHeader(HttpReqHead.AC_PROPERTY_ID, ac_property_id)); + return this; + } + + /** + * 指定请求和响应遵循的缓存机制 + * 例如:Cache-Control: no-cache + * + * @param cacheControl cache-control + * @return 返回当前对象 + */ + public HttpHeaderBuilder cacheControl(String cacheControl) { + headerMaps.put(HttpReqHead.CACHE_CONTROL, + new BasicHeader(HttpReqHead.CACHE_CONTROL, cacheControl)); + return this; + } + + /** + * 表示是否需要持久连接(HTTP 1.1默认进行持久连接) + * 例如:Connection: close 短链接; Connection: keep-alive 长连接 + * + * @param connection connection + * @return 返回当前对象 + */ + public HttpHeaderBuilder connection(String connection) { + headerMaps.put(HttpReqHead.CONNECTION, + new BasicHeader(HttpReqHead.CONNECTION, connection)); + return this; + } + + /** + * HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器 + * 例如:Cookie: $Version=1; Skin=new; + * + * @param cookie cookie + * @return 返回当前对象 + */ + public HttpHeaderBuilder cookie(String cookie) { + headerMaps.put(HttpReqHead.COOKIE, + new BasicHeader(HttpReqHead.COOKIE, cookie)); + return this; + } + + /** + * 请求内容长度 + * 例如:Content-Length: 348 + * + * @param contentLength content-length + * @return 返回当前对象 + */ + public HttpHeaderBuilder contentLength(String contentLength) { + headerMaps.put(HttpReqHead.CONTENT_LENGTH, + new BasicHeader(HttpReqHead.CONTENT_LENGTH, contentLength)); + return this; + } + + /** + * 请求的与实体对应的MIME信息 + * 例如:Content-Type: application/x-www-form-urlencoded + * + * @param contentType content-type + * @return 返回当前对象 + */ + public HttpHeaderBuilder contentType(String contentType) { + headerMaps.put(HttpReqHead.CONTENT_TYPE, + new BasicHeader(HttpReqHead.CONTENT_TYPE, contentType)); + return this; + } + + /** + * 请求发送的日期和时间 + * 例如:Date: Tue, 15 Nov 2010 08:12:31 GMT + * + * @param date date + * @return 返回当前对象 + */ + public HttpHeaderBuilder date(String date) { + headerMaps.put(HttpReqHead.DATE, + new BasicHeader(HttpReqHead.DATE, date)); + return this; + } + + /** + * 请求的特定的服务器行为 + * 例如:Expect: 100-continue + * + * @param expect expect + * @return 返回当前对象 + */ + public HttpHeaderBuilder expect(String expect) { + headerMaps.put(HttpReqHead.EXPECT, + new BasicHeader(HttpReqHead.EXPECT, expect)); + return this; + } + + /** + * 发出请求的用户的Email + * 例如:From: user@email.com + * + * @param from from + * @return 返回当前对象 + */ + public HttpHeaderBuilder from(String from) { + headerMaps.put(HttpReqHead.FROM, + new BasicHeader(HttpReqHead.FROM, from)); + return this; + } + + /** + * 指定请求的服务器的域名和端口号 + * 例如:Host: blog.csdn.net + * + * @param host host + * @return 返回当前对象 + */ + public HttpHeaderBuilder host(String host) { + headerMaps.put(HttpReqHead.HOST, + new BasicHeader(HttpReqHead.HOST, host)); + return this; + } + + /** + * 只有请求内容与实体相匹配才有效 + * 例如:If-Match: “737060cd8c284d8af7ad3082f209582d” + * + * @param ifMatch if-match + * @return 返回当前对象 + */ + public HttpHeaderBuilder ifMatch(String ifMatch) { + headerMaps.put(HttpReqHead.IF_MATCH, + new BasicHeader(HttpReqHead.IF_MATCH, ifMatch)); + return this; + } + + /** + * 如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码 + * 例如:If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT + * + * @param ifModifiedSince if-modified-Since + * @return 返回当前对象 + */ + public HttpHeaderBuilder ifModifiedSince(String ifModifiedSince) { + headerMaps.put(HttpReqHead.IF_MODIFIED_SINCE, + new BasicHeader(HttpReqHead.IF_MODIFIED_SINCE, ifModifiedSince)); + return this; + } + + /** + * 如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变 + * 例如:If-None-Match: “737060cd8c284d8af7ad3082f209582d” + * + * @param ifNoneMatch if-none-match + * @return 返回当前对象 + */ + public HttpHeaderBuilder ifNoneMatch(String ifNoneMatch) { + headerMaps.put(HttpReqHead.IF_NONE_MATCH, + new BasicHeader(HttpReqHead.IF_NONE_MATCH, ifNoneMatch)); + return this; + } + + /** + * 如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。参数也为Etag + * 例如:If-Range: “737060cd8c284d8af7ad3082f209582d” + * + * @param ifRange if-range + * @return 返回当前对象 + */ + public HttpHeaderBuilder ifRange(String ifRange) { + headerMaps.put(HttpReqHead.IF_RANGE, + new BasicHeader(HttpReqHead.IF_RANGE, ifRange)); + return this; + } + + /** + * 只在实体在指定时间之后未被修改才请求成功 + * 例如:If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT + * + * @param ifUnmodifiedSince if-unmodified-since + * @return 返回当前对象 + */ + public HttpHeaderBuilder ifUnmodifiedSince(String ifUnmodifiedSince) { + headerMaps.put(HttpReqHead.IF_UNMODIFIED_SINCE, + new BasicHeader(HttpReqHead.IF_UNMODIFIED_SINCE, ifUnmodifiedSince)); + return this; + } + + /** + * 限制信息通过代理和网关传送的时间 + * 例如:Max-Forwards: 10 + * + * @param maxForwards max-forwards + * @return 返回当前对象 + */ + public HttpHeaderBuilder maxForwards(String maxForwards) { + headerMaps.put(HttpReqHead.MAX_FORWARDS, + new BasicHeader(HttpReqHead.MAX_FORWARDS, maxForwards)); + return this; + } + + /** + * 用来包含实现特定的指令 + * 例如:Pragma: no-cache + * + * @param pragma pragma + * @return 返回当前对象 + */ + public HttpHeaderBuilder pragma(String pragma) { + headerMaps.put(HttpReqHead.PRAGMA, + new BasicHeader(HttpReqHead.PRAGMA, pragma)); + return this; + } + + /** + * 连接到代理的授权证书 + * 例如:Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== + * + * @param proxyAuthorization proxy-authorization + * @return 返回当前对象 + */ + public HttpHeaderBuilder proxyAuthorization(String proxyAuthorization) { + headerMaps.put(HttpReqHead.PROXY_AUTHORIZATION, + new BasicHeader(HttpReqHead.PROXY_AUTHORIZATION, proxyAuthorization)); + return this; + } + + /** + * 只请求实体的一部分,指定范围 + * 例如:Range: bytes=500-999 + * + * @param range range + * @return 返回当前对象 + */ + public HttpHeaderBuilder range(String range) { + headerMaps.put(HttpReqHead.RANGE, + new BasicHeader(HttpReqHead.RANGE, range)); + return this; + } + + /** + * 先前网页的地址,当前请求网页紧随其后,即来路 + * 例如:Referer: http://www.zcmhi.com/archives/71.html + * + * @param referer referer + * @return 返回当前对象 + */ + public HttpHeaderBuilder referer(String referer) { + headerMaps.put(HttpReqHead.REFERER, + new BasicHeader(HttpReqHead.REFERER, referer)); + return this; + } + + /** + * 客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息 + * 例如:TE: trailers,deflate;q=0.5 + * + * @param te te + * @return 返回当前对象 + */ + public HttpHeaderBuilder te(String te) { + headerMaps.put(HttpReqHead.TE, + new BasicHeader(HttpReqHead.TE, te)); + return this; + } + + /** + * 向服务器指定某种传输协议以便服务器进行转换(如果支持) + * 例如:Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11 + * + * @param upgrade upgrade + * @return 返回当前对象 + */ + public HttpHeaderBuilder upgrade(String upgrade) { + headerMaps.put(HttpReqHead.UPGRADE, + new BasicHeader(HttpReqHead.UPGRADE, upgrade)); + return this; + } + + /** + * User-Agent的内容包含发出请求的用户信息 + * + * @param userAgent user-agent + * @return 返回当前对象 + */ + public HttpHeaderBuilder userAgent(String userAgent) { + headerMaps.put(HttpReqHead.USER_AGENT, + new BasicHeader(HttpReqHead.USER_AGENT, userAgent)); + return this; + } + + /** + * 关于消息实体的警告信息 + * 例如:Warn: 199 Miscellaneous warning + * + * @param warning warning + * @return 返回当前对象 + */ + public HttpHeaderBuilder warning(String warning) { + headerMaps.put(HttpReqHead.WARNING, + new BasicHeader(HttpReqHead.WARNING, warning)); + return this; + } + + /** + * 通知中间网关或代理服务器地址,通信协议 + * 例如:Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) + * + * @param via via + * @return 返回当前对象 + */ + public HttpHeaderBuilder via(String via) { + headerMaps.put(HttpReqHead.VIA, + new BasicHeader(HttpReqHead.VIA, via)); + return this; + } + + /** + * 设置此HTTP连接的持续时间(超时时间) + * 例如:Keep-Alive: 300 + * + * @param keepAlive keep-alive + * @return 返回当前对象 + + */ + public HttpHeaderBuilder keepAlive(String keepAlive) { + headerMaps.put(HttpReqHead.KEEP_ALIVE, + new BasicHeader(HttpReqHead.KEEP_ALIVE, keepAlive)); + return this; + } + + public String accept() { + return get(HttpReqHead.ACCEPT); + } + + public String acceptCharset() { + return get(HttpReqHead.ACCEPT_CHARSET); + } + + public String acceptEncoding() { + return get(HttpReqHead.ACCEPT_ENCODING); + } + + public String acceptLanguage() { + return get(HttpReqHead.ACCEPT_LANGUAGE); + } + + public String acceptRanges() { + return get(HttpReqHead.ACCEPT_RANGES); + } + + public String authorization() { + return get(HttpReqHead.AUTHORIZATION); + } + + public String cacheControl() { + return get(HttpReqHead.CACHE_CONTROL); + } + + public String connection() { + return get(HttpReqHead.CONNECTION); + } + + public String cookie() { + return get(HttpReqHead.COOKIE); + } + + public String contentLength() { + return get(HttpReqHead.CONTENT_LENGTH); + } + + public String contentType() { + return get(HttpReqHead.CONTENT_TYPE); + } + + public String date() { + return get(HttpReqHead.DATE); + } + + public String expect() { + return get(HttpReqHead.EXPECT); + } + + public String from() { + return get(HttpReqHead.FROM); + } + + public String host() { + return get(HttpReqHead.HOST); + } + + public String ifMatch() { + return get(HttpReqHead.IF_MATCH); + } + + public String ifModifiedSince() { + return get(HttpReqHead.IF_MODIFIED_SINCE); + } + + public String ifNoneMatch() { + return get(HttpReqHead.IF_NONE_MATCH); + } + + public String ifRange() { + return get(HttpReqHead.IF_RANGE); + } + + public String ifUnmodifiedSince() { + return get(HttpReqHead.IF_UNMODIFIED_SINCE); + } + + public String maxForwards() { + return get(HttpReqHead.MAX_FORWARDS); + } + + public String pragma() { + return get(HttpReqHead.PRAGMA); + } + + public String proxyAuthorization() { + return get(HttpReqHead.PROXY_AUTHORIZATION); + } + + public String referer() { + return get(HttpReqHead.REFERER); + } + + public String te() { + return get(HttpReqHead.TE); + } + + public String upgrade() { + return get(HttpReqHead.UPGRADE); + } + + public String userAgent() { + return get(HttpReqHead.USER_AGENT); + } + + public String via() { + return get(HttpReqHead.VIA); + } + + public String warning() { + return get(HttpReqHead.WARNING); + } + + public String keepAlive() { + return get(HttpReqHead.KEEP_ALIVE); + } + + + /** + * 获取head信息 + * + * @return + */ + private String get(String headName) { + if (headerMaps.containsKey(headName)) { + return headerMaps.get(headName).getValue(); + } + return null; + } + + /** + * 返回header头信息 + * + * @return 返回构建的header头信息数组 + */ + public Header[] build() { + Header[] headers = new Header[headerMaps.size()]; + int i = 0; + for (Header header : headerMaps.values()) { + headers[i] = header; + i++; + } + headerMaps.clear(); + headerMaps = null; + return headers; + } + + /** + * Http头信息 + * + * @author arron + * @date 2015年11月9日 上午11:29:04 + * @version 1.0 + */ + private static class HttpReqHead { + public static final String ACCEPT = "Accept"; + public static final String ACCEPT_CHARSET = "Accept-Charset"; + public static final String ACCEPT_ENCODING = "Accept-Encoding"; + public static final String ACCEPT_LANGUAGE = "Accept-Language"; + public static final String ACCEPT_RANGES = "Accept-Ranges"; + public static final String AUTHORIZATION = "Authorization"; + public static final String AC_PROPERTY_ID = "AC-Property-Id"; + public static final String CACHE_CONTROL = "Cache-Control"; + public static final String CONNECTION = "Connection"; + public static final String COOKIE = "Cookie"; + public static final String CONTENT_LENGTH = "Content-Length"; + public static final String CONTENT_TYPE = "Content-Type"; + public static final String DATE= "Date"; + public static final String EXPECT = "Expect"; + public static final String FROM = "From"; + public static final String HOST = "Host"; + public static final String IF_MATCH = "If-Match"; + public static final String IF_MODIFIED_SINCE = "If-Modified-Since"; + public static final String IF_NONE_MATCH = "If-None-Match"; + public static final String IF_RANGE = "If-Range"; + public static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since"; + public static final String KEEP_ALIVE = "Keep-Alive"; + public static final String MAX_FORWARDS = "Max-Forwards"; + public static final String PRAGMA = "Pragma"; + public static final String PROXY_AUTHORIZATION = "Proxy-Authorization"; + public static final String RANGE = "Range"; + public static final String REFERER = "Referer"; + public static final String TE = "TE"; + public static final String UPGRADE = "Upgrade"; + public static final String USER_AGENT = "User-Agent"; + public static final String VIA = "Via"; + public static final String WARNING = "Warning"; + } + + /** + * 常用头信息配置 + * + * @author arron + * @version 1.0 + */ + public static class Headers{ + public static final String APP_FORM_URLENCODED="application/x-www-form-urlencoded"; + public static final String TEXT_PLAIN="text/plain"; + public static final String TEXT_HTML="text/html"; + public static final String TEXT_XML="text/xml"; + public static final String TEXT_JSON="text/json"; + public static final String CONTENT_CHARSET_ISO_8859_1 = StandardCharsets.ISO_8859_1.name(); + public static final String CONTENT_CHARSET_UTF8 = StandardCharsets.UTF_8.name(); + public static final String DEF_PROTOCOL_CHARSET = StandardCharsets.US_ASCII.name(); + public static final String CONN_CLOSE = "close"; + public static final String KEEP_ALIVE = "keep-alive"; + public static final String EXPECT_CONTINUE = "100-continue"; + } + + + + + + public static Map getDefaultHeaders(URLConnection connection) { + Map defaultHeaders = new HashMap<>(); + defaultHeaders.put(HttpHeader.ACCEPT, "*/*"); + defaultHeaders.put(HttpHeader.CONNECTION, "Keep-Alive"); + defaultHeaders.put(HttpHeader.USER_AGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); + defaultHeaders.put(HttpHeader.ACCEPT_CHARSET, "utf-8"); + return defaultHeaders; + } + + /** + * 設置請求頭到連接對象 + * + * @param conn URL連接對象 + * @param contentType 內容類型 + * @param headers HTTP 請求頭 Map(可選,如果為 null 或空則使用默認值) + */ + public static void setRequestHeaders(URLConnection conn, String contentType, Map headers) { + Map defaultHeaders = getDefaultHeaders(conn); + // 如果傳入了自定義 headers,則合併(自定義的優先) + if (headers != null && !headers.isEmpty()) { + defaultHeaders.putAll(headers); + } + // 設置所有請求頭 + for (Map.Entry entry : defaultHeaders.entrySet()) { + conn.setRequestProperty(entry.getKey(), entry.getValue()); + } + // Content-Type 優先級最高,如果指定了則覆蓋 + if (contentType != null) { + conn.setRequestProperty("Content-Type", contentType); + } + } +} diff --git a/src/main/java/com/mgm/mcrm/common/httpclient/HttpParameterBuilder.java b/src/main/java/com/mgm/mcrm/common/httpclient/HttpParameterBuilder.java new file mode 100644 index 0000000..ec7d889 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/httpclient/HttpParameterBuilder.java @@ -0,0 +1,72 @@ +package com.mgm.mcrm.common.httpclient; + + +import com.alibaba.fastjson.JSON; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * HTTP 参数构建器 + * + * 用于构建 HTTP 请求参数(查询字符串、请求体等)。 + * + * @author Aaka + */ +public class HttpParameterBuilder { + private static final Logger log = LoggerFactory.getLogger(HttpParameterBuilder.class); + + /** + * 將參數 Map 轉換為查詢字符串(用於 GET 請求) + * + * @param params 參數 Map + * @return 查詢字符串,格式為 name1=value1&name2=value2 + */ + public static String buildQueryString(Map params) { + if (params == null || params.isEmpty()) { + return ""; + } + return params.entrySet().stream() + .filter(entry -> entry.getKey() != null && entry.getValue() != null) + .map(entry -> { + try { + String key = URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8); + String value = URLEncoder.encode(String.valueOf(entry.getValue()), StandardCharsets.UTF_8); + return key + "=" + value; + } catch (Exception e) { + log.warn("Failed to encode parameter: {}={}", entry.getKey(), entry.getValue(), e); + return null; + } + }) + .filter(java.util.Objects::nonNull) + .collect(Collectors.joining("&")); + } + + + /** + * 將參數 Map 轉換為請求體字符串 + * + * @param params 參數 Map + * @param contentType 內容類型 + * @return 請求體字符串 + */ + public static String buildRequestBody(Map params, String contentType) { + if (params == null || params.isEmpty()) { + return ""; + } + // 如果是 JSON 格式 + if (contentType != null && contentType.contains("application/json")) { + // 使用 FastJSON 將 Map 轉換為 JSON 字符串 + return JSON.toJSONString(params); + } else { + // 默認使用 form-urlencoded 格式 + return buildQueryString(params); + } + } + +} + diff --git a/src/main/java/com/mgm/mcrm/common/httpclient/HttpRequestOptions.java b/src/main/java/com/mgm/mcrm/common/httpclient/HttpRequestOptions.java new file mode 100644 index 0000000..98dcd79 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/httpclient/HttpRequestOptions.java @@ -0,0 +1,375 @@ +package com.mgm.mcrm.common.httpclient; + +import com.mgm.mcrm.common.enums.HttpMethods; +import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.entity.mime.Header; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.util.Timeout; + +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.util.HashMap; +import java.util.Map; + +public class HttpRequestOptions { + + private HttpRequestOptions(){}; + + /** + * 获取实例 + * @return 返回当前对象 + */ + public static HttpRequestOptions create(){ + return new HttpRequestOptions(); + } + + + /** + * HttpClient对象 + */ + private HttpClient client; + + /** + * Header头信息 + */ + private Header[] headers; + + /** + * 是否返回response的headers + */ + private boolean isReturnRespHeaders; + + /** + * 请求方法 + */ + private HttpMethods method=HttpMethods.POST; + + /** + * 请求方法名称 + */ + private String methodName; + + /** + * 用于cookie操作 + */ + private HttpContext context; + + // private Map map; + + /** + * 以json格式作为输入参数 + */ + private String json; + + /** + * 输入输出编码 + */ + private String encoding= Charset.defaultCharset().displayName(); + + /** + * 输入编码 + */ + private String inenc; + + /** + * 输出编码 + */ + private String outenc; + + /** + * 设置RequestConfig + */ + private RequestConfig requestConfig; + + /** + * 解决多线程下载时,strean被close的问题 + */ + private static final ThreadLocal outs = new ThreadLocal(); + + /** + * 解决多线程处理时,url被覆盖问题 + */ + private static final ThreadLocal urls = new ThreadLocal(); + + /** + * 解决多线程处理时,url被覆盖问题 + */ + private static final ThreadLocal> maps = new ThreadLocal>(); + + /** + * @param client HttpClient对象 + * @return 返回当前对象 + */ + public HttpRequestOptions client(HttpClient client) { + this.client = client; + return this; + } + + /** + * @param url 资源url + * @return 返回当前对象 + */ + public HttpRequestOptions url(String url) { + urls.set(url); + return this; + } + + /** + * @param headers Header头信息 + * @return 返回当前对象 + */ + public HttpRequestOptions headers(Header[] headers) { + this.headers = headers; + return this; + } + + /** + * Header头信息(是否返回response中的headers) + * + * @param headers Header头信息 + * @param isReturnRespHeaders 是否返回response中的headers + * @return 返回当前对象 + */ + public HttpRequestOptions headers(Header[] headers, boolean isReturnRespHeaders) { + this.headers = headers; + this.isReturnRespHeaders=isReturnRespHeaders; + return this; + } + + /** + * @param method 请求方法 + * @return 返回当前对象 + */ + public HttpRequestOptions method(HttpMethods method) { + this.method = method; + return this; + } + + /** + * @param methodName 请求方法 + * @return 返回当前对象 + */ + public HttpRequestOptions methodName(String methodName) { + this.methodName = methodName; + return this; + } + + /** + * @param context cookie操作相关 + * @return 返回当前对象 + */ + public HttpRequestOptions context(HttpContext context) { + this.context = context; + return this; + } + + /** + * @param map 传递参数 + * @return 返回当前对象 + */ + public HttpRequestOptions map(Map map) { +// synchronized (getClass()) { +// if(this.map==null || map==null){ +// this.map = map; +// }else { +// this.map.putAll(map);; +// } +// } + Map m = maps.get(); + if(m == null || map.isEmpty()){ + m = map; + }else { + m.putAll(map); + } + maps.set(m); + return this; + } + + /** + * @param json 以json格式字符串作为参数 + * @return 返回当前对象 + */ + public HttpRequestOptions json(String json) { + this.json = json; + Map map = new HashMap(); + map.put(HttpEntityBuilder.ENTITY_JSON, json); + maps.set(map); + return this; + } + + /** + * @param filePaths 待上传文件所在路径 + * @return 返回当前对象 + */ + public HttpRequestOptions files(String[] filePaths) { + return files(filePaths, "file"); + } + /** + * 上传文件时用到 + * @param filePaths 待上传文件所在路径 + * @param inputName 即file input 标签的name值,默认为file + * @return 返回当前对象 + */ + public HttpRequestOptions files(String[] filePaths, String inputName) { + return files(filePaths, inputName, false); + } + /** + * 上传文件时用到 + * @param filePaths 待上传文件所在路径 + * @param inputName 即file input 标签的name值,默认为file + * @param forceRemoveContentTypeChraset 是否强制一处content-type中设置的编码类型 + * @return 返回当前对象 + */ + public HttpRequestOptions files(String[] filePaths, String inputName, boolean forceRemoveContentTypeChraset) { +// synchronized (getClass()) { +// if(this.map==null){ +// this.map= new HashMap(); +// } +// } +// map.put(Utils.ENTITY_MULTIPART, filePaths); +// map.put(Utils.ENTITY_MULTIPART+".name", inputName); +// map.put(Utils.ENTITY_MULTIPART+".rmCharset", forceRemoveContentTypeChraset); + + Map m = maps.get(); + if(m.isEmpty()){ + m = new HashMap(); + } + m.put(HttpEntityBuilder.ENTITY_MULTIPART, filePaths); + m.put(HttpEntityBuilder.ENTITY_MULTIPART+".name", inputName); + m.put(HttpEntityBuilder.ENTITY_MULTIPART+".rmCharset", forceRemoveContentTypeChraset); + maps.set(m); + return this; + } + + /** + * @param encoding 输入输出编码 + * @return 返回当前对象 + */ + public HttpRequestOptions encoding(String encoding) { + //设置输入输出 + inenc(encoding); + outenc(encoding); + this.encoding = encoding; + return this; + } + + /** + * @param inenc 输入编码 + */ + public void inenc(String inenc) { + this.inenc = inenc; + } + + /** + * @param outenc 输出编码 + */ + public void outenc(String outenc) { + this.outenc = outenc; + } + + /** + * @param out 输出流对象 + * @return 返回当前对象 + */ + public HttpRequestOptions out(OutputStream out) { + outs.set(out); + return this; + } + + /** + * 设置超时时间 + * + * @param timeout 超市时间,单位-毫秒 + * @return 返回当前对象 + */ + public HttpRequestOptions timeout(int timeout){ + return timeout(timeout, true); + } + + /** + * 设置超时时间以及是否允许网页重定向(自动跳转 302) + * + * @param timeout 超时时间,单位-毫秒 + * @param redirectEnable 自动跳转 + * @return 返回当前对象 + */ + public HttpRequestOptions timeout(int timeout, boolean redirectEnable){ + // 配置请求的超时设置 + // 注意:HttpClient 5 中需要使用 Timeout 对象,而不是直接的 int 值 + Timeout timeoutValue = Timeout.ofMilliseconds(timeout); + RequestConfig config = RequestConfig.custom() + .setConnectionRequestTimeout(timeoutValue) + .setResponseTimeout(timeoutValue) + .setRedirectsEnabled(redirectEnable) + .build(); + return timeout(config); + } + + /** + * 设置代理、超时时间、允许网页重定向等 + * + * @param requestConfig 超时时间,单位-毫秒 + * @return 返回当前对象 + */ + public HttpRequestOptions timeout(RequestConfig requestConfig){ + this.requestConfig = requestConfig; + return this; + } + + public HttpClient client() { + return client; + } + + public Header[] headers() { + return headers; + } + public boolean isReturnRespHeaders() { + return isReturnRespHeaders; + } + + public String url() { + return urls.get(); + } + + public HttpMethods method() { + return method; + } + + public String methodName() { + return methodName; + } + + public HttpContext context() { + return context; + } + + public Map map() { +// return map; + return maps.get(); + } + + public String json() { + return json; + } + + public String encoding() { + return encoding; + } + + public String inenc() { + return inenc == null ? encoding : inenc; + } + + public String outenc() { + return outenc == null ? encoding : outenc; + } + + public OutputStream out() { + return outs.get(); + } + + public RequestConfig requestConfig() { + return requestConfig; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/httpclient/HttpSslSupport.java b/src/main/java/com/mgm/mcrm/common/httpclient/HttpSslSupport.java new file mode 100644 index 0000000..25e4df5 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/httpclient/HttpSslSupport.java @@ -0,0 +1,197 @@ +package com.mgm.mcrm.common.httpclient; + +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.core5.ssl.SSLContexts; + +import javax.net.ssl.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; + +/** + * SSL 工具类(基于 HttpClient 5) + * + * 提供: + * - 信任所有证书的 SSLSocketFactory + * - 信任所有证书的 SSLConnectionSocketFactory + * + * 注意:默认实现信任所有证书,仅适用于内部系统或测试环境。 + * + * @author Anka + * @version 2.0 (client5) + */ +public class HttpSslSupport { + private static final SSLHandler SIMPLE_VERIFIER = new SSLHandler(); + + private static SSLSocketFactory sslFactory; + // 注意:SSLConnectionSocketFactory 在 HttpClient 5 中被标记为 deprecated, + // 但这是目前唯一可用的方式,新的 API 尚未稳定 + @SuppressWarnings("deprecation") + private static SSLConnectionSocketFactory sslConnFactory; + + private static final HttpSslSupport INSTANCE = new HttpSslSupport(); + + private SSLContext sc; + + public static HttpSslSupport getInstance() { + return INSTANCE; + } + + public static HttpSslSupport custom() { + return new HttpSslSupport(); + } + + /** + * 重写 X509TrustManager 和 HostnameVerifier,信任所有证书与主机名。 + * 仅推荐在内部环境或调试场景使用。 + */ + private static class SSLHandler implements X509TrustManager, HostnameVerifier { + + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return new java.security.cert.X509Certificate[]{}; + } + + @Override + public void checkServerTrusted(java.security.cert.X509Certificate[] chain, + String authType) throws CertificateException { + // 信任所有服务器证书 + } + + @Override + public void checkClientTrusted(java.security.cert.X509Certificate[] chain, + String authType) throws CertificateException { + // 信任所有客户端证书 + } + + @Override + public boolean verify(String paramString, SSLSession paramSSLSession) { + // 信任所有主机名 + return true; + } + } + + /** + * 获取默认 HostnameVerifier(信任所有主机名) + */ + public static HostnameVerifier getVerifier() { + return SIMPLE_VERIFIER; + } + + /** + * 获取信任所有证书的 {@link SSLSocketFactory} + */ + public synchronized SSLSocketFactory getSSLSF(SSLProtocolVersion sslpv) { + if (sslFactory != null) { + return sslFactory; + } + try { + SSLContext context = getSSLContext(sslpv); + context.init(null, new TrustManager[]{SIMPLE_VERIFIER}, null); + sslFactory = context.getSocketFactory(); + return sslFactory; + } catch (KeyManagementException e) { + throw new RuntimeException("初始化 SSLSocketFactory 失败", e); + } + } + + /** + * 获取信任所有证书的 {@link SSLConnectionSocketFactory}(HttpClient5) + * + * 注意:SSLConnectionSocketFactory 在 HttpClient 5 中被标记为 deprecated, + * 但这是目前唯一可用的方式,新的 API 尚未稳定 + */ + @SuppressWarnings("deprecation") + public synchronized SSLConnectionSocketFactory getSSLCONNSF(SSLProtocolVersion sslpv) { + if (sslConnFactory != null) { + return sslConnFactory; + } + try { + SSLContext context = getSSLContext(sslpv); + context.init(null, new TrustManager[]{SIMPLE_VERIFIER}, new java.security.SecureRandom()); + sslConnFactory = new SSLConnectionSocketFactory(context, SIMPLE_VERIFIER); + return sslConnFactory; + } catch (KeyManagementException e) { + throw new RuntimeException("初始化 SSLConnectionSocketFactory 失败", e); + } + } + + /** + * 使用自定义证书(trustStore)初始化 SSLContext + */ + public HttpSslSupport customSSL(String keyStorePath, String keyStorepass) { + FileInputStream instream = null; + try { + KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + instream = new FileInputStream(new File(keyStorePath)); + trustStore.load(instream, keyStorepass.toCharArray()); + // 相信自己的 CA 和所有自签名证书 + this.sc = SSLContexts.custom() + .loadTrustMaterial(trustStore, (chain, authType) -> true) + .build(); + return this; + } catch (KeyManagementException | KeyStoreException | + NoSuchAlgorithmException | CertificateException | IOException e) { + throw new RuntimeException("初始化自定义 SSLContext 失败", e); + } finally { + if (instream != null) { + try { + instream.close(); + } catch (IOException ignore) { + // ignore + } + } + } + } + + /** + * 获取(或创建)指定协议版本的 {@link SSLContext} + */ + public SSLContext getSSLContext(SSLProtocolVersion sslpv) { + try { + if (this.sc == null) { + this.sc = SSLContext.getInstance(sslpv.getName()); + } + return this.sc; + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("不支持的 SSL 协议版本: " + sslpv.getName(), e); + } + } + + /** + * 支持的 SSL/TLS 协议版本枚举 + */ + public enum SSLProtocolVersion { + SSL("SSL"), + SSLv3("SSLv3"), + TLSv1("TLSv1"), + TLSv1_1("TLSv1.1"), + TLSv1_2("TLSv1.2"), + TLSv1_3("TLSv1.3"); + + private final String name; + + SSLProtocolVersion(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + + public static SSLProtocolVersion find(String name) { + for (SSLProtocolVersion pv : SSLProtocolVersion.values()) { + if (pv.getName().equalsIgnoreCase(name)) { + return pv; + } + } + throw new IllegalArgumentException("未支持当前 SSL 版本号:" + name); + } + + } +} diff --git a/src/main/java/com/mgm/mcrm/common/interceptor/ControllerLogAspector.java b/src/main/java/com/mgm/mcrm/common/interceptor/ControllerLogAspector.java new file mode 100644 index 0000000..e6c67f4 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/interceptor/ControllerLogAspector.java @@ -0,0 +1,117 @@ +package com.mgm.mcrm.common.interceptor; + +import java.lang.reflect.Method; + +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.StringUtils; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.annotation.logging.OperationLog; +import com.mgm.mcrm.logging.models.SysLogOperation; +import com.mgm.mcrm.logging.models.SysLogLogin; +import com.mgm.mcrm.logging.services.SysLogOperationService; +import com.mgm.mcrm.logging.services.SysLogLoginService; +import com.mgm.mcrm.common.utils.LogUtil; + +@Aspect // 表示一个切面bean +@Component // bean容器的组件注解。虽然放在contrller包里,但它不是控制器。如果注入service,但我们又没有放在service包里 +@Order(3) // 有多个日志时,ORDER可以定义切面的执行顺序(数字越大,前置越后执行,后置越前执行) +public class ControllerLogAspector { + @Resource + private SysLogOperationService sysLogOperationService; + @Resource + private SysLogLoginService sysLogLoginService; + //定义切入点 + /*1、execution 表达式主体 + 2、第1个* 表示返回值类型 *表示所有类型 + 3、包名 com.*.*.controller下 + 4、第4个* 类名,com.*.*.controller包下所有类 + 5、第5个* 方法名,com.*.*.controller包下所有类所有方法 + 6、(..) 表示方法参数,..表示任何参数 + */ + @Pointcut("execution(public * com.mgm.mcrm..*.*Controller.*(..))") + public void ControllerLog() { + + } + + @Before("ControllerLog()") + public void doBefore(JoinPoint joinPoint) { + } + + @AfterReturning(returning="returnObject", pointcut= "ControllerLog()") + public void doAfterReturn(JoinPoint joinPoint, Object returnObject) { + try { + //--獲得調用的方法以及參數類型 + Signature invokeSignature = joinPoint.getSignature(); + String methodName = invokeSignature.getName(); + Class[] parameterTypes = ((MethodSignature)invokeSignature).getMethod().getParameterTypes(); + Method invokeMmethod = invokeSignature.getDeclaringType().getMethod(methodName,parameterTypes); + boolean isLogController = invokeMmethod.isAnnotationPresent(OperationLog.class); + //--檢測到需要寫DBLog的注釋 + if(isLogController) { + OperationLog operLogTag = invokeMmethod.getAnnotation(OperationLog.class); + ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + HttpServletRequest request = attributes.getRequest(); + Object invokeObject=null; + Object resultObject=null; + Object oldDataObject = null; + boolean isRunSuccess=true; + String sLogMessage = ""; + if(returnObject instanceof BaseApiResponse processResult) { + isRunSuccess = processResult.isSuccess(); + invokeObject = processResult.getRequestData(); + resultObject = processResult.getData(); + oldDataObject = processResult.getRequestData(); + sLogMessage = processResult.getLogMessage(); + }else { + resultObject = returnObject; + } + if(invokeObject==null) { + invokeObject = request.getParameterMap(); + } + if(!SysCommon.dbDebugLog) { + invokeObject = null; + resultObject = null; + oldDataObject = null; + } + int successFlag = 1; + if(!isRunSuccess) { + successFlag = 0; + } + // 如果log有内容,則寫入DB log + if(StringUtils.isNotBlank(sLogMessage)) { + if("login".equalsIgnoreCase(operLogTag.actionName())) { + SysLogLogin logLogin = SysCommon.createLogLoginByRequest(request, operLogTag.eventCode(),invokeObject,resultObject,sLogMessage,successFlag,oldDataObject); + sysLogLoginService.save(logLogin); + }else { + SysLogOperation logOperation = SysCommon.createLogOperationByRequest(request, operLogTag.eventCode(),invokeObject,resultObject,sLogMessage,successFlag,oldDataObject); + sysLogOperationService.save(logOperation); + } + } + } + + }catch(Exception err) { + LogUtil.error(ControllerLogAspector.class, "[ControllerLogAspector][doAfterReturn] " + err.getMessage()); + } + } + + @AfterReturning("ControllerLog()") + public void doAfter(JoinPoint joinPoint) { + + } + +} diff --git a/src/main/java/com/mgm/mcrm/common/jms/AppControlMsgConsumer.java b/src/main/java/com/mgm/mcrm/common/jms/AppControlMsgConsumer.java new file mode 100644 index 0000000..2fd4d01 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/jms/AppControlMsgConsumer.java @@ -0,0 +1,58 @@ +package com.mgm.mcrm.common.jms; + +import jakarta.annotation.Resource; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.Strings; +import org.springframework.jms.annotation.JmsListener; +import org.springframework.stereotype.Component; + +import com.alibaba.fastjson2.JSONObject; + +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.dtos.msg.AppSettingMsgData; +import com.mgm.mcrm.common.dtos.msg.JMSTextMessage; +import com.mgm.mcrm.common.dtos.system.AppServerState; +import com.mgm.mcrm.common.services.SysServerStateService; + +@Slf4j +@Component +public class AppControlMsgConsumer { + @Resource + private SysServerStateService serverStateService; + + @JmsListener(destination = "${app_ctrl_topic}", containerFactory = "jmsTopicListenerCF") + public void receive(String msg){ + JMSTextMessage msgObject = null; + + try { + + msgObject = JSONObject.parseObject(msg, JMSTextMessage.class); + + if(Strings.CS.equals("SYNC_SERVER_STATE", msgObject.getMsgType())) { + + AppServerState serverInfo = + JSONObject.parseObject(msgObject.getMsgContent(), AppServerState.class); + + if(serverInfo != null) { + SysCommon.registerServerInfo(serverInfo); + } + + } else if(Strings.CS.equals("UPD_MOBILE_CFG", msgObject.getMsgType())) { + + AppSettingMsgData updateRequest = + JSONObject.parseObject(msgObject.getMsgContent(), AppSettingMsgData.class); + + serverStateService.updateCfgByRequest(updateRequest); + + } else if(Strings.CS.equals("REQ_SYNC_SERVER_STATE", msgObject.getMsgType())) { + + serverStateService.notifyCurrentState(); + } + + } catch(Exception err) { + + log.error("Process JMS message failed. msgType={}, message={}", msgObject != null ? msgObject.getMsgType() : "UNKNOWN", msg, err); + } + } +} diff --git a/src/main/java/com/mgm/mcrm/common/jms/AppControlMsgSender.java b/src/main/java/com/mgm/mcrm/common/jms/AppControlMsgSender.java new file mode 100644 index 0000000..cc5174d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/jms/AppControlMsgSender.java @@ -0,0 +1,47 @@ +package com.mgm.mcrm.common.jms; + +import org.apache.activemq.command.ActiveMQTopic; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.stereotype.Component; + +import com.alibaba.fastjson2.JSON; + +import com.mgm.mcrm.common.dtos.msg.JMSTextMessage; +import com.mgm.mcrm.common.utils.LogUtil; + +@Component +public class AppControlMsgSender { + + @Value("${app_ctrl_topic}") + private String ctrlTopicName; + private ActiveMQTopic ctrlTopic=null; + + @Autowired + private JmsTemplate jmsTemplate; + + private ActiveMQTopic getTopic() { + return this.ctrlTopic==null?new ActiveMQTopic(ctrlTopicName):this.ctrlTopic; + } + + public void sendMessage(String message) { + jmsTemplate.convertAndSend(getTopic(), message); + } + + public boolean sendMessage(String msgType, Object msgData) { + boolean result =false; + try { + JMSTextMessage msg = new JMSTextMessage(); + msg.setMsgType(msgType); + msg.setMsgContent(msgData==null?"":JSON.toJSONString(msgData)); + String message = JSON.toJSONString(msg); + jmsTemplate.convertAndSend(getTopic(), message); + result=true; + }catch(Exception err) { + LogUtil.error(AppControlMsgSender.class, "Send JMS Failed:"+err.getMessage()); + result=false; + } + return result; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/jms/BookingControlMsgConsumer.java b/src/main/java/com/mgm/mcrm/common/jms/BookingControlMsgConsumer.java new file mode 100644 index 0000000..b2a985a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/jms/BookingControlMsgConsumer.java @@ -0,0 +1,97 @@ +package com.mgm.mcrm.common.jms; + +import com.alibaba.fastjson2.JSON; +import com.mgm.mcrm.booking.dtos.BookingDto; +import com.mgm.mcrm.booking.models.Bookings; +import jakarta.annotation.Resource; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.jms.annotation.JmsListener; +import org.springframework.stereotype.Component; + +import com.alibaba.fastjson2.JSONObject; + +import com.mgm.mcrm.booking.repositories.BookingDao; +import com.mgm.mcrm.common.dtos.msg.JMSTextMessage; +import com.mgm.mcrm.booking.services.BookingService; + +import java.util.List; + +@Slf4j +@Component +public class BookingControlMsgConsumer { + @Resource + private BookingService bookingService; + @Resource + private BookingDao bookingDao; + + @JmsListener(destination = "${book_ctrl_queue}", containerFactory = "jmsQueueListenerCF") + public void receive(String msg){ + + JMSTextMessage msgObject = null; + + try { + + msgObject = JSONObject.parseObject(msg, JMSTextMessage.class); + + String msgType = msgObject.getMsgType(); + if("CREATE_DAYLIGHT_BOOKING".equals(msgType)) { + Bookings booking = + JSONObject.parseObject(msgObject.getMsgContent(), Bookings.class); + bookingService.callDaylightUpsertReservation( + booking, + "CREATE_BOOKING" + ); + } else if("CREATE_OPERA_BOOKING".equals(msgType)) { + Bookings booking = + JSONObject.parseObject(msgObject.getMsgContent(), Bookings.class); + + bookingService.callOWSCreateBooking(booking); + } else if("EDIT_BOOKING".equals(msgType)) { + Bookings booking = + JSONObject.parseObject(msgObject.getMsgContent(), Bookings.class); + bookingService.callOWSEditBooking(booking); + } else if("WAITLIST_BOOKING".equals(msgType)) { + bookingService.finishWaitlistBooking(); + } else if("SYNC_MERGE_BOOKING".equals(msgType)) { + + List syncBookings = null; + try { + syncBookings = + JSON.parseArray( + msgObject.getMsgContent(), + BookingDto.class + ); + } catch(Exception err){ + log.error("Convert sync booking data error", err); + } + + bookingService.updateMergeBookingToDb_Optimize(syncBookings); + } + } catch(Exception err) { + + try { + if(msgObject != null + && "CREATE_DAYLIGHT_BOOKING".equals(msgObject.getMsgType())) { + + Bookings booking = + JSONObject.parseObject( + msgObject.getMsgContent(), + Bookings.class + ); + + bookingDao.updateProcessStatus( + booking.getId(), + 0 + ); + } + + } catch(Exception updateErr){ + + log.error("Update booking process status failed", updateErr); + } + + log.error("Process booking JMS message failed. msgType={}, message={}", msgObject != null ? msgObject.getMsgType() : "UNKNOWN", msg, err); + } + } +} diff --git a/src/main/java/com/mgm/mcrm/common/jms/BookingControlMsgSender.java b/src/main/java/com/mgm/mcrm/common/jms/BookingControlMsgSender.java new file mode 100644 index 0000000..022a4fc --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/jms/BookingControlMsgSender.java @@ -0,0 +1,51 @@ +package com.mgm.mcrm.common.jms; + +import org.apache.activemq.command.ActiveMQQueue; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.jms.core.JmsTemplate; +import org.springframework.stereotype.Component; + +import com.alibaba.fastjson2.JSON; + +import com.mgm.mcrm.common.dtos.msg.JMSTextMessage; +import com.mgm.mcrm.common.utils.LogUtil; + +@Component +public class BookingControlMsgSender { + + @Value("${book_ctrl_queue}") + private String ctrlQueueName; + + private ActiveMQQueue ctrlQueue = null; + + @Autowired + private JmsTemplate jmsTemplate; + + private ActiveMQQueue getQueue() { + if (ctrlQueue == null) { + ctrlQueue = new ActiveMQQueue(ctrlQueueName); + } + return ctrlQueue; + } + + public void sendMessage(String message) { + jmsTemplate.convertAndSend(getQueue(), message); + } + + public boolean sendMessage(String msgType, Object msgData) { + + try { + JMSTextMessage msg = new JMSTextMessage(); + msg.setMsgType(msgType); + msg.setMsgContent(msgData == null ? "" : JSON.toJSONString(msgData)); + String message = JSON.toJSONString(msg); + jmsTemplate.convertAndSend(getQueue(), message); + return true; + }catch(Exception err) { + LogUtil.error(BookingControlMsgSender.class, "Send JMS Failed:" + err.getMessage()); + return false; + } + + } +} diff --git a/src/main/java/com/mgm/mcrm/common/listener/ConfigListener.java b/src/main/java/com/mgm/mcrm/common/listener/ConfigListener.java new file mode 100644 index 0000000..37c19c9 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/listener/ConfigListener.java @@ -0,0 +1,60 @@ +package com.mgm.mcrm.common.listener; + +import java.util.List; + +import jakarta.annotation.Resource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.event.ApplicationStartedEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.context.MessageSource; +import org.springframework.stereotype.Component; + +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.jms.AppControlMsgSender; +import com.mgm.mcrm.appsetting.models.SysSetting; +import com.mgm.mcrm.common.dtos.system.AppServerState; +import com.mgm.mcrm.appsetting.services.SysSettingService; +import com.mgm.mcrm.common.utils.ExcelUtils; +import com.mgm.mcrm.common.utils.NetworkUtil; + +@Component +public class ConfigListener implements ApplicationListener { + @Value("${internal_network_pattern}") + private String internalIpPattern; + @Value("${allow_origin}") + private String allowOrigins; + @Value("${soap_servers}") + private String soapServers; + @Value("${http_api_servers}") + private String httpApiServers; + @Value("${allow_ip}") + private String allowIP; + @Resource + private SysSettingService sysSettingService; + @Autowired + private AppControlMsgSender ctrlMsgSender; + + @Override + public void onApplicationEvent(ApplicationStartedEvent event) { + + MessageSource i18nMessage = (MessageSource)event.getApplicationContext().getBean("messageSource"); + SysCommon.setMessageSource(i18nMessage); + SysCommon.initRuntimePath(); + SysCommon.loadSystemConfig(); + // load settings from DB + List sysSettings = sysSettingService.getSysSettingsAll(); + SysCommon.loadSettingsFromDB(sysSettings); + SysCommon.loadSecurityConfig(allowOrigins); + SysCommon.loadSoapServerConfig(soapServers); + SysCommon.loadApiServerConfig(httpApiServers); + SysCommon.loadAllowIPConfig(allowIP); + ExcelUtils.loadExcelDefines(); + if(ctrlMsgSender!=null) { + AppServerState serverState = SysCommon.refreshAppServerState(); + SysCommon.jmsRunning = ctrlMsgSender.sendMessage("REQ_SYNC_SERVER_STATE",serverState); + } + NetworkUtil.setInternalIpPattern(internalIpPattern); + } +} diff --git a/src/main/java/com/mgm/mcrm/common/schedule/AppSystemScheduleJob.java b/src/main/java/com/mgm/mcrm/common/schedule/AppSystemScheduleJob.java new file mode 100644 index 0000000..0040a5b --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/schedule/AppSystemScheduleJob.java @@ -0,0 +1,27 @@ +package com.mgm.mcrm.common.schedule; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.services.SysServerStateService; + +@Component +public class AppSystemScheduleJob { + + @Autowired + private SysServerStateService serverStateService; + + @Scheduled(fixedDelay = 60000) + public void notifyServerState() { + try { + if(StringUtils.isNotBlank(SysCommon.serverIp)) { + serverStateService.notifyCurrentState(); + } + }catch(Exception err) { + + } + } +} diff --git a/src/main/java/com/mgm/mcrm/common/schedule/BookingScheduleJob.java b/src/main/java/com/mgm/mcrm/common/schedule/BookingScheduleJob.java new file mode 100644 index 0000000..6d65bd6 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/schedule/BookingScheduleJob.java @@ -0,0 +1,109 @@ +package com.mgm.mcrm.common.schedule; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import com.mgm.mcrm.appsetting.models.CfgSettings; +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.booking.models.GamingData; +import com.mgm.mcrm.booking.services.BookingService; +import jakarta.annotation.Resource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import com.mgm.mcrm.booking.repositories.BookingDao; +import com.mgm.mcrm.booking.repositories.GamingDataDao; +import com.mgm.mcrm.common.jms.BookingControlMsgSender; +//import com.mgm.mcrm.booking.services.BookingService; +import com.mgm.mcrm.notification.services.EmailTemplateService; +import com.mgm.mcrm.appsetting.services.SettingService; +import com.mgm.mcrm.booking.services.WaitlistBookingService; +import com.mgm.mcrm.common.utils.DateTimeUtil; + +@Component +public class BookingScheduleJob { + @Autowired + private BookingControlMsgSender ctrlMsgSender; + @Resource + private WaitlistBookingService waitlistBookingService; + @Resource + private SettingService settingService; + @Resource + private BookingService bookingService; + + @Scheduled(fixedDelay = 300000) + public void expiryWaitlistBooking() { + try { + CfgSettings cutoffStartTime = settingService.getSettingByKey("VIEW_YESTERDAY_TODOLIST_START"); + String cutoffStartTimeValue = cutoffStartTime.getKeyValues(); + CfgSettings cutoffEndTime = settingService.getSettingByKey("VIEW_YESTERDAY_TODOLIST_END"); + String cutoffEndTimeValue = cutoffEndTime.getKeyValues(); + Date curoffDate = DateTimeUtil.getTodoYesterdayDay(cutoffStartTimeValue, cutoffEndTimeValue); + Date currentDate = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd"); + + if(curoffDate.getTime() == currentDate.getTime()) { + List bookList = waitlistBookingService.getExpiryWaitlistBooking(); + while(!bookList.isEmpty()) { + Bookings book = bookList.getFirst(); + waitlistBookingService.expiryWaitlistBooking(book); + bookList = waitlistBookingService.getExpiryWaitlistBooking(); + } + + } + }catch(Exception err) { + err.printStackTrace(); + } + } + + @Scheduled(fixedDelay = 120000) + public void syncGamingData() { + try { + List bookings = waitlistBookingService.getPendingWaitlistBooking(); + if(bookings.size()>0) { + ArrayList bookIds = new ArrayList(); + for(Bookings b:bookings) { + List getGaming = waitlistBookingService.findGamingDataByBookId(b.getId()); + if(getGaming==null||getGaming.size()==0) { + bookIds.add(String.valueOf(b.getId())); + } + } + if(bookIds.size()>0) { + String bookId = String.join(";", bookIds); + List gamingData = waitlistBookingService.syncWaitlistData(bookId); + } + } + + }catch(Exception err) { + err.printStackTrace(); + } + } + + @Scheduled(fixedDelay = 3000) + public void finishFailedBooking() { + try { + List bookings = bookingService.getFailedBooking(); + while(!bookings.isEmpty()) { + Bookings book = bookings.getFirst(); + int res = bookingService.updateProcessStatus(book.getId()); + if(res>0) { + if(book.getRevisionOf()!=null) { + ctrlMsgSender.sendMessage("EDIT_BOOKING", book); + }else { + if("DAYLIGHT".equals(book.getCategory())) { + ctrlMsgSender.sendMessage("CREATE_DAYLIGHT_BOOKING", book); + }else{ + ctrlMsgSender.sendMessage("CREATE_OPERA_BOOKING", book); + } + + } + } + bookings = bookingService.getFailedBooking(); + } + }catch(Exception err) { + err.printStackTrace(); + } + } +} diff --git a/src/main/java/com/mgm/mcrm/common/services/HttpService.java b/src/main/java/com/mgm/mcrm/common/services/HttpService.java new file mode 100644 index 0000000..6dc02fa --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/services/HttpService.java @@ -0,0 +1,210 @@ +package com.mgm.mcrm.common.services; + +import com.alibaba.fastjson.JSON; +import com.mgm.mcrm.common.dtos.HttpResult; +import com.mgm.mcrm.common.enums.HttpMethods; +import com.mgm.mcrm.common.httpclient.HttpClientExecutor; +import com.mgm.mcrm.common.httpclient.HttpRequestOptions; +import jakarta.annotation.Resource; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.core5.http.Header; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.Map; + +/** + * 請求服務 + * + * @author Aaka + */ +@Service +public class HttpService { + + private static final Logger log = LoggerFactory.getLogger(HttpService.class); + + + @Resource + @Qualifier("httpClientWithSSL") + private CloseableHttpClient httpClient; + + @Resource + @Qualifier("httpRequestConfig") + private RequestConfig requestConfig; + + @Value("${daylight.url}") + private String daylightUrl; + + public String sslGet(String url, Header[] headers, Map map) throws Exception { + + // todo 在這裏需要把請求頭的信息插入到數據庫裏 + log.info("======sslGet======url:{}===========headers:{} =============== map:{}", daylightUrl + url, JSON.toJSONString(headers), JSON.toJSONString(map)); + // 使用 HttpConfig 配置 GET 请求(带参数) + HttpRequestOptions getConfig = HttpRequestOptions.create() + .url(daylightUrl + url) + .timeout(requestConfig) + .map(map) + .encoding("utf-8") + .client(httpClient); + + String result = HttpClientExecutor.get(getConfig, headers); + log.info("====== GET request result:{}", result); + + return result; + } + + public String sslGetNoLog(String url, Header[] headers, Map map) throws Exception { + + // todo 在這裏需要把請求頭的信息插入到數據庫裏 + log.info("======sslGet======url:{}===========headers:{} =============== map:{}", daylightUrl + url, JSON.toJSONString(headers), JSON.toJSONString(map)); + // 使用 HttpConfig 配置 GET 请求(带参数) + HttpRequestOptions getConfig = HttpRequestOptions.create() + .url(daylightUrl + url) + .timeout(requestConfig) + .map(map) + .encoding("utf-8") + .client(httpClient); + + String result = HttpClientExecutor.get(getConfig, headers); + log.info("====== GET request result size={}", result.length()); + + return result; + } + + public HttpResult sslGetHttpResult(String url, Header[] headers, Map map) throws Exception { + + // todo 在這裏需要把請求頭的信息插入到數據庫裏 + log.info("======sslGet======url:{}===========headers:{} =============== map:{}", daylightUrl + url, JSON.toJSONString(headers), JSON.toJSONString(map)); + // 使用 HttpConfig 配置 GET 请求(带参数) + HttpRequestOptions getConfig = HttpRequestOptions.create() + .url(daylightUrl + url) + .timeout(requestConfig) + .map(map) + .encoding("utf-8") + .client(httpClient); + + HttpResult result = HttpClientExecutor.sendAndGetResp(getConfig, headers); + log.info("====== GET request result:{}", result.getResult()); + + return result; + } + + /** + * 使用 HttpConfig 配置 PUT 请求 + * + * @param url 請求路徑 + * @param headers 請求頭 + * @param map 請求參數 + * @return 接口結果的json數據 + * @throws Exception 異常 + */ + public String sslPut(String url, Header[] headers, Map map) throws Exception { + log.info("======sslPut======url:{}===========headers:{} =============== map:{}", daylightUrl + url, JSON.toJSONString(headers), JSON.toJSONString(map)); + HttpRequestOptions putConfig = HttpRequestOptions.create() + .url(daylightUrl + url) + .timeout(requestConfig) + .method(HttpMethods.PUT) + .json(JSON.toJSONString(map)) + .encoding("utf-8") + .client(httpClient); + String result = HttpClientExecutor.send(putConfig, headers); + log.info("====== PUT request result:{}", result); + + return result; + } + + /** + * 使用 HttpConfig 配置 Delete 请求 + * + * @param url 請求路徑 + * @param headers 請求頭 + * @param requestBody 請求參數 + * @return 接口結果的json數據 + * @throws Exception 異常 + */ + public String sslDelete(String url, Header[] headers, Object requestBody) throws Exception { + log.info("======sslDelete======url:{}===========headers:{} =============== map:{}", daylightUrl + url, JSON.toJSONString(headers), JSON.toJSONString(requestBody)); + HttpRequestOptions deleteConfig = HttpRequestOptions.create() + .url(daylightUrl + url) + .timeout(requestConfig) + .json(JSON.toJSONString(requestBody)) + .method(HttpMethods.DELETE) + .client(httpClient); + String result = HttpClientExecutor.send(deleteConfig, headers); + log.info("====== DELETE request result:{}", result); + return result; + } + + /** + * 使用 HttpConfig 配置 Post 请求 + * + * @param url 請求路徑 + * @param headers 請求頭 + * @param requestBody request 数据 + * @return 接口結果的json數據 + * @throws Exception 異常 + */ + public HttpResult sslPost(String url, Header[] headers, Object requestBody) throws Exception { + log.info("======sslCreatePost======url:{}===========headers:{}", daylightUrl + url, JSON.toJSONString(headers)); + HttpRequestOptions postConfig = HttpRequestOptions.create() + .url(daylightUrl + url) + .timeout(requestConfig) + .json(JSON.toJSONString(requestBody)) + .method(HttpMethods.POST) + .client(httpClient); + HttpResult result = HttpClientExecutor.sendAndPostResp(postConfig, headers); +// System.out.println("POST 请求结果:\n" + result); + log.info("====== POST request result:{}", result); + return result; + } + + /** + * 使用 HttpConfig 配置 PATCH 请求(JSON 请求体) + * + * @param url 請求路徑 + * @param headers 請求頭 + * @param requestBody request 数据 + * @return 接口結果的json數據 + * @throws Exception 異常 + */ + public HttpResult sslPatch(String url, Header[] headers, Object requestBody) throws Exception { + log.info("======sslCreatePatch======url:{}===========headers:{}", daylightUrl + url, JSON.toJSONString(headers)); + HttpRequestOptions patchConfig = HttpRequestOptions.create() + .url(daylightUrl + url) + .timeout(requestConfig) + .json(JSON.toJSONString(requestBody)) + .method(HttpMethods.PATCH) + .encoding("utf-8") + .client(httpClient); + HttpResult result = HttpClientExecutor.sendAndPatchResp(patchConfig, headers); + log.info("====== PATCH request result:{}", result); + return result; + } + + /** + * 使用 HttpConfig 配置 Delete 请求 + * + * @param url 請求路徑 + * @param headers 請求頭 + * @param map Cancel数据 + * @return 接口結果的json數據 + * @throws Exception 異常 + */ + public HttpResult sslCancelPost(String url, Header[] headers, Map map) throws Exception { + log.info("======sslCancelPost======url:{}===========headers:{}", daylightUrl + url, JSON.toJSONString(headers)); + HttpRequestOptions postConfig = HttpRequestOptions.create() + .url(daylightUrl + url) + .timeout(requestConfig) + .json(JSON.toJSONString(map)) + .method(HttpMethods.POST) + .client(httpClient); + HttpResult result = HttpClientExecutor.sendAndPostResp(postConfig, headers); +// System.out.println("POST 请求结果:\n" + result); + log.info("====== POST request result:{}", result); + return result; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/services/HttpTokenService.java.bak b/src/main/java/com/mgm/mcrm/common/services/HttpTokenService.java.bak new file mode 100644 index 0000000..a162176 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/services/HttpTokenService.java.bak @@ -0,0 +1,573 @@ +package com.mgm.mcrm.common.services; + +import com.alibaba.fastjson.JSON; +import com.mgm.mcrm.basesetting.property.dtos.response.TokenResponse; +import com.mgm.mcrm.common.dtos.CachedToken; +import com.mgm.mcrm.common.dtos.HttpResult; +import com.mgm.mcrm.common.enums.HttpMethods; +import com.mgm.mcrm.common.httpclient.HttpClientExecutor; +import com.mgm.mcrm.common.httpclient.HttpRequestOptions; +import com.mgm.mcrm.common.httpclient.HttpHeaderBuilder; +import com.mgm.mcrm.common.httpclient.HttpSslSupport; +import com.mgm.mcrm.common.utils.LogUtil; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.core5.http.Header; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Slf4j +@Service +public class HttpTokenService { + @Resource + private HttpService httpService; + + @Resource + @Qualifier("httpClientWithSSL") + private CloseableHttpClient httpClient; + + @Resource + @Qualifier("httpRequestConfig") + private RequestConfig requestConfig; + + @Value("${token.url}") + private String tokenUrl; + + @Value("${token.username}") + private String username; + + @Value("${token.password}") + private String password; + + @Value("${token.grant-type}") + private String grantType; + + @Value("${token.client-id}") + private String clientId; + + @Value("${token.client-secret}") + private String clientSecret; + + // Token 缓存,key 为 url,value 为缓存的 token 信息 + private final ConcurrentHashMap tokenCache = new ConcurrentHashMap<>(); + + // Token 过期时间:800 毫秒 + private static final long TOKEN_EXPIRE_TIME_MS = 80000; + // 重试间隔时间:1秒 + private static final long RETRY_DELAY_MS = 1000; + + public TokenResponse getToken() throws Exception { + String url = "/connect/token"; + // 1. 先检查缓存 + CachedToken cachedToken = tokenCache.get(url); + + if (cachedToken != null && !cachedToken.isExpired()) { + // 缓存未过期,直接返回 + LogUtil.info(HttpTokenService.class, "=========get token from cache"+cachedToken.getToken()); + return cachedToken.getToken(); + } + if (cachedToken != null && cachedToken.isExpired()) { + // 緩存過期,重新获取 token(使用 username/password) + // 注意:这里不使用 refresh_token,因为需要保存 refresh_token 才能使用 + // 如果后续需要支持 refresh_token,需要修改逻辑 + log.info("Cached token expired, will get new token"); + String re = byToken(url); + if (re == null || re.contains("\"error\"")) { + log.error("Failed to get new token after cache expired, response: {}", re); + throw new Exception("Failed to get new token: " + re); + } + TokenResponse tokenResponse = JSON.parseObject(re, TokenResponse.class); + if (tokenResponse == null || tokenResponse.getAccess_token() == null) { + log.error("Invalid token response after cache expired: {}", re); + throw new Exception("Invalid token response: " + re); + } + long expireTime = System.currentTimeMillis() + TOKEN_EXPIRE_TIME_MS; + tokenCache.put(url, new CachedToken(tokenResponse, expireTime)); + LogUtil.info(HttpTokenService.class, "=========get new token after cache expired"); + return tokenResponse; + } + String re = byToken(url); + if (re == null || re.contains("\"error\"")) { + log.error("Failed to get token, response: {}", re); + throw new Exception("Failed to get token: " + re); + } + TokenResponse tokenResponse = JSON.parseObject(re, TokenResponse.class); + if (tokenResponse == null || tokenResponse.getAccess_token() == null) { + log.error("Invalid token response: {}", re); + throw new Exception("Invalid token response: " + re); + } + // 3. 将新获取的 token 放入缓存 + long expireTime = System.currentTimeMillis() + TOKEN_EXPIRE_TIME_MS; + tokenCache.put(url, new CachedToken(tokenResponse, expireTime)); + + return tokenResponse; + } + + + /** + * 构建请求头 + */ + private Header[] buildHeaders() { + return HttpHeaderBuilder.custom() + .contentType("application/x-www-form-urlencoded") + .build(); + } + + /** + * 构建请求参数 Map + */ + private Map buildTokenRequestParams() { + Map map = new HashMap<>(); + map.put("username", username); + map.put("password", password); + map.put("grant_type", grantType); + map.put("client_id", clientId); + map.put("client_secret", clientSecret); + + // 验证关键参数不为空 + if (clientId == null || clientId.trim().isEmpty()) { + log.error("client_id is null or empty!"); + } + if (clientSecret == null || clientSecret.trim().isEmpty()) { + log.error("client_secret is null or empty!"); + } + if (grantType == null || grantType.trim().isEmpty()) { + log.error("grant_type is null or empty!"); + } + + return map; + } + + /** + * 检查响应是否有效(包含有效的 access_token) + */ + private boolean isValidTokenResponse(String response) { + if (response == null || response.trim().isEmpty()) { + return false; + } + + try { + // 检查是否包含错误信息 + if (response.contains("\"error\"")) { + log.warn("Token response contains error: {}", response); + return false; + } + + TokenResponse tokenResponse = JSON.parseObject(response, TokenResponse.class); + return tokenResponse != null && tokenResponse.getAccess_token() != null + && !tokenResponse.getAccess_token().trim().isEmpty(); + } catch (Exception e) { + log.error("Failed to parse token response: {}", response, e); + return false; + } + } + + /** + * 检查是否是认证相关的错误(不应该重试) + */ + private boolean isAuthenticationError(String response) { + if (response == null) { + return false; + } + // 检查常见的认证错误 + return response.contains("\"error\"") && ( + response.contains("invalid_client") || + response.contains("invalid_grant") || + response.contains("unauthorized_client") || + response.contains("unsupported_grant_type") + ); + } + + /** + * 发送 token 请求(带重试机制) + * 如果第一次失败(网络错误或临时错误),等待1秒后重试一次 + * 如果是业务错误(如 invalid_client),不重试 + */ + private String sendTokenRequestWithRetry(String url) { + // 第一次尝试 + RequestResult firstResult = sendTokenRequestWithDetails(url); + String token = firstResult.responseBody; + + // 记录第一次请求是否到达服务器 + log.info("First attempt - ReachedServer: {}, StatusCode: {}, Response: {}", + firstResult.reachedServer, firstResult.statusCode, + token != null && token.length() > 100 ? token.substring(0, 100) + "..." : token); + + // 检查响应是否有效 + if (!isValidTokenResponse(token)) { + // 如果响应包含认证错误信息(如 invalid_client),不重试 + if (isAuthenticationError(token)) { + Map params = buildTokenRequestParams(); + log.error("Token request failed with authentication error, will not retry. URL: {}, StatusCode: {}, ReachedServer: {}, Error: {}, params:{}", + url, firstResult.statusCode, firstResult.reachedServer, token, + params); + return token; + } + + // 如果是其他错误(非认证错误),也不重试 + if (token != null && token.contains("\"error\"")) { + Map params = buildTokenRequestParams(); + log.error("Token request failed with error response, will not retry. URL: {}, StatusCode: {}, ReachedServer: {}, Error: {}, params:{}", + url, firstResult.statusCode, firstResult.reachedServer, token, + params); + return token; + } + + // 判断是否需要重试 + // 只有在请求未到达服务器(网络错误)时才重试 + if (!firstResult.reachedServer) { + log.warn("First attempt did not reach server, will retry after {} ms. URL: {}, Exception: {}", + RETRY_DELAY_MS, url, + firstResult.exception != null ? firstResult.exception.getMessage() : "Unknown error"); + + try { + Thread.sleep(RETRY_DELAY_MS); + + // 重试时重新构建参数,确保参数是全新的 + RequestResult retryResult = sendTokenRequestWithDetails(url); + String retryToken = retryResult.responseBody; + + log.info("Retry attempt - ReachedServer: {}, StatusCode: {}, Response: {}", + retryResult.reachedServer, retryResult.statusCode, + retryToken != null && retryToken.length() > 100 ? retryToken.substring(0, 100) + "..." : retryToken); + + // 如果重试时也返回错误,记录详细信息 + if (retryToken != null && retryToken.contains("\"error\"")) { + log.error("Retry also failed with error. URL: {}, First attempt (ReachedServer: {}, StatusCode: {}), Retry (ReachedServer: {}, StatusCode: {}), Error: {}", + url, firstResult.reachedServer, firstResult.statusCode, + retryResult.reachedServer, retryResult.statusCode, retryToken); + } + + if (isValidTokenResponse(retryToken)) { + log.info("Successfully retrieved token from url: {} on retry", url); + return retryToken; + } else { + log.error("Failed to retrieve token from url: {} after retry. First (ReachedServer: {}), Retry (ReachedServer: {}, StatusCode: {})", + url, firstResult.reachedServer, retryResult.reachedServer, retryResult.statusCode); + return retryToken; // 返回重试的结果,即使失败 + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.error("Thread interrupted while waiting for retry", e); + return token; // 返回第一次的结果 + } + } else { + // 请求到达了服务器但返回了无效响应,不重试 + log.warn("Request reached server but returned invalid response, will not retry. URL: {}, StatusCode: {}, Response: {}", + url, firstResult.statusCode, token); + return token; + } + } + + return token; + } + + /** + * 请求结果包装类 + */ + private static class RequestResult { + String responseBody; + Integer statusCode; + boolean reachedServer; + Exception exception; + + RequestResult(String responseBody, Integer statusCode, boolean reachedServer, Exception exception) { + this.responseBody = responseBody; + this.statusCode = statusCode; + this.reachedServer = reachedServer; + this.exception = exception; + } + } + + /** + * 发送 token 请求(单次),返回详细结果包括状态码 + */ + private RequestResult sendTokenRequestWithDetails(String url) { + long startTime = System.currentTimeMillis(); + try { + Map params = buildTokenRequestParams(); + Header[] headers = buildHeaders(); + + // 构建完整的 URL + String fullUrl = tokenUrl + url; + + log.debug("Sending token request to url: {}, with params: client_id={}, grant_type={}", + fullUrl, params.get("client_id"), params.get("grant_type")); + + // 使用 HttpClientUtil.sendPostAndGetResp 获取详细响应信息(包括状态码) + HttpRequestOptions postFormConfig = HttpRequestOptions.create() + .url(fullUrl) + .timeout(requestConfig) + .method(HttpMethods.POST) + .map(params) + .encoding("utf-8") + .client(httpClient); + + HttpResult httpResult = HttpClientExecutor.sendAndPostResp(postFormConfig, headers); + + long duration = System.currentTimeMillis() - startTime; + int statusCode = httpResult.getStatusCode(); + String responseBody = httpResult.getResult(); + + // 判断请求是否到达服务器 + // 如果有 HTTP 状态码(即使是错误码如 400, 401, 500),说明请求到达了服务器 + boolean reachedServer = (statusCode > 0); + + log.info("Token request completed - URL: {}, StatusCode: {}, ReachedServer: {}, Duration: {}ms, Response: {},header:{}", + fullUrl, statusCode, reachedServer, duration, + responseBody != null && responseBody.length() > 200 + ? responseBody.substring(0, 200) + "..." : responseBody,headers); + + return new RequestResult(responseBody, statusCode, reachedServer, null); + + } catch (Exception e) { + long duration = System.currentTimeMillis() - startTime; + log.error("Failed to retrieve token from url: {}, Duration: {}ms, Exception: {}", + tokenUrl + url, duration, e.getMessage(), e); + + // 根据异常类型判断是否到达服务器 + boolean reachedServer = isServerReachableException(e); + + return new RequestResult(null, null, reachedServer, e); + } + } + + /** + * 判断异常类型,确定请求是否可能到达了服务器 + */ + private boolean isServerReachableException(Exception e) { + if (e == null) { + return false; + } + + String exceptionMessage = e.getMessage(); + String exceptionClass = e.getClass().getName(); + + // 如果异常信息包含 HTTP 状态码相关的内容,可能到达了服务器 + if (exceptionMessage != null && ( + exceptionMessage.contains("status") || + exceptionMessage.contains("HTTP") || + exceptionMessage.contains("400") || + exceptionMessage.contains("401") || + exceptionMessage.contains("403") || + exceptionMessage.contains("500") + )) { + return true; + } + + // 连接超时、DNS 解析失败等异常,说明未到达服务器 + if (exceptionClass.contains("ConnectTimeoutException") || + exceptionClass.contains("SocketTimeoutException") || + exceptionClass.contains("UnknownHostException") || + exceptionClass.contains("NoRouteToHostException") || + exceptionMessage != null && ( + exceptionMessage.contains("timeout") || + exceptionMessage.contains("Connection refused") || + exceptionMessage.contains("Name or service not known") + )) { + return false; + } + + // 其他异常,默认认为可能到达了服务器(保守判断) + return true; + } + + /** + * 发送 token 请求(单次)- 兼容旧接口 + */ + private String sendTokenRequest(String url) { + RequestResult result = sendTokenRequestWithDetails(url); + return result.responseBody; + } + + /** + * 获取新 token(带重试) + */ + private String byToken(String url) { + return sendTokenRequestWithRetry(url); + } + + /** + * 测试用的 main 函数 - 循环请求测试 + * 参数写死,直接运行即可 + */ + public static void main(String[] args) throws Exception { + // 写死的测试参数 + String testUrl = "/connect/token"; + int loopCount = 200; // 循环次数 + long intervalMs = 100; // 每次请求间隔(毫秒) + + System.out.println("========== 开始 Token 请求循环测试 =========="); + System.out.println("URL: " + testUrl); + System.out.println("循环次数: " + loopCount); + System.out.println("请求间隔: " + intervalMs + "ms"); + System.out.println("=============================================\n"); + + // 手动创建必要的依赖对象 + CloseableHttpClient httpClient = createHttpClient(); + RequestConfig requestConfig = createRequestConfig(); + HttpService httpService = createHttpService(httpClient, requestConfig); + + // 创建 HttpTokenService 实例 + HttpTokenService tokenService = new HttpTokenService(); + + // 手动设置参数(写死的配置) + tokenService.tokenUrl = "https://eu1.api.uat.development.abovecloud.io"; + tokenService.username = "mcrm.ifc@MGMDEV"; + tokenService.password = "Shiji@123"; + tokenService.grantType = "password"; + tokenService.clientId = "3rd.willtech_technology"; + tokenService.clientSecret = "HJIvAynCSCqvjEe8MC9K"; + + // 设置依赖对象 + tokenService.httpClient = httpClient; + tokenService.requestConfig = requestConfig; + tokenService.httpService = httpService; + + int successCount = 0; + int failCount = 0; + long totalTime = 0; + + try { + for (int i = 1; i <= loopCount; i++) { + try { + System.out.println("---------- 第 " + i + " 次请求 ----------"); + long startTime = System.currentTimeMillis(); + + // 调用 getToken 方法 + TokenResponse tokenResponse = tokenService.getToken(); + + long duration = System.currentTimeMillis() - startTime; + totalTime += duration; + + if (tokenResponse != null && tokenResponse.getAccess_token() != null) { + successCount++; + String tokenPreview = tokenResponse.getAccess_token().length() > 20 + ? tokenResponse.getAccess_token().substring(0, 20) + "..." + : tokenResponse.getAccess_token(); + System.out.println("✓ 请求成功 - 耗时: " + duration + "ms"); + System.out.println(" AccessToken: " + tokenPreview); + } else { + failCount++; + System.out.println("✗ 请求失败 - 响应为空或无效"); + } + + // 如果不是最后一次,等待 + if (i < loopCount) { + System.out.println("等待 " + intervalMs + "ms 后进行下一次请求...\n"); + Thread.sleep(intervalMs); + } + + } catch (Exception e) { + failCount++; + System.err.println("✗ 第 " + i + " 次请求异常: " + e.getMessage()); + e.printStackTrace(); + + if (i < loopCount) { + try { + Thread.sleep(intervalMs); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + break; + } + } + } + } + } finally { + // 关闭 HttpClient + if (httpClient != null) { + httpClient.close(); + } + } + + // 输出统计 + System.out.println("\n============================================="); + System.out.println("========== Token 请求测试完成 =========="); + System.out.println("总请求次数: " + loopCount); + System.out.println("成功次数: " + successCount); + System.out.println("失败次数: " + failCount); + if (loopCount > 0) { + System.out.println("成功率: " + String.format("%.2f%%", (successCount * 100.0 / loopCount))); + System.out.println("平均耗时: " + (totalTime / loopCount) + "ms"); + } + System.out.println("总耗时: " + totalTime + "ms"); + System.out.println("============================================="); + } + + /** + * 手动创建 HttpClient + */ + private static CloseableHttpClient createHttpClient() { + try { + HttpSslSupport ssls = HttpSslSupport.getInstance(); + @SuppressWarnings("deprecation") + org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory sslConnFactory = + ssls.getSSLCONNSF(HttpSslSupport.SSLProtocolVersion.TLSv1_2); + + @SuppressWarnings("deprecation") + org.apache.hc.core5.http.config.Registry registry = + org.apache.hc.core5.http.config.RegistryBuilder.create() + .register("https", sslConnFactory) + .build(); + + @SuppressWarnings("deprecation") + org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager connManager = + new org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager(registry); + connManager.setMaxTotal(100); + connManager.setDefaultMaxPerRoute(10); + + RequestConfig config = createRequestConfig(); + + return org.apache.hc.client5.http.impl.classic.HttpClients.custom() + .setConnectionManager(connManager) + .setDefaultRequestConfig(config) + .setConnectionManagerShared(false) + .build(); + } catch (Exception e) { + throw new RuntimeException("创建 HttpClient 失败", e); + } + } + + /** + * 手动创建 RequestConfig + */ + private static RequestConfig createRequestConfig() { + return RequestConfig.custom() + .setConnectionRequestTimeout(org.apache.hc.core5.util.Timeout.ofSeconds(5)) + .setResponseTimeout(org.apache.hc.core5.util.Timeout.ofSeconds(10)) + .setRedirectsEnabled(false) + .build(); + } + + /** + * 手动创建 HttpService + */ + private static HttpService createHttpService(CloseableHttpClient httpClient, RequestConfig requestConfig) { + HttpService httpService = new HttpService(); + // 使用反射设置私有字段 + try { + java.lang.reflect.Field httpClientField = HttpService.class.getDeclaredField("httpClient"); + httpClientField.setAccessible(true); + httpClientField.set(httpService, httpClient); + + java.lang.reflect.Field requestConfigField = HttpService.class.getDeclaredField("requestConfig"); + requestConfigField.setAccessible(true); + requestConfigField.set(httpService, requestConfig); + + java.lang.reflect.Field tokenUrlField = HttpService.class.getDeclaredField("tokenUrl"); + tokenUrlField.setAccessible(true); + tokenUrlField.set(httpService, "https://eu1.api.uat.development.abovecloud.io"); + } catch (Exception e) { + throw new RuntimeException("设置 HttpService 字段失败", e); + } + return httpService; + } + +} diff --git a/src/main/java/com/mgm/mcrm/common/services/MGMApiService.java b/src/main/java/com/mgm/mcrm/common/services/MGMApiService.java new file mode 100644 index 0000000..c5a4e16 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/services/MGMApiService.java @@ -0,0 +1,419 @@ +package com.mgm.mcrm.common.services; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.mgm.mcrm.booking.dtos.search.DateRange; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson.JSONObject; +import com.google.gson.Gson; + +import com.mgm.mcrm.common.dtos.http_util.HttpRequestDefine; +import com.mgm.mcrm.common.dtos.http_util.HttpResponseResult; +import com.mgm.mcrm.common.constants.SysCommon; +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; + +@Service +public class MGMApiService { + public static String ESB_APP_ID = ""; + public static String ESB_APP_SECRET = ""; + public static String ESB_Server = ""; + public static String ESB_ACCESS_TOKEN = null; + public static Date ESB_EXPIRED_TIME = new Date(); + + private static final String API_GET_ACCESS_TOKEN = "/RequestAccessToken"; + private static final String API_GET_PLAYER_PROFILE = "/GetReportingLinePlayerInfo"; + private static final String API_CHECK_PLAYER_TPD = "/GetRoomBookingQualificationStatus"; + private static final String API_GET_USER_INFO = "/GetLoginUserInfo"; + private static final String API_NON_MGM_BOOKING = "/GetNonMGMRoomBookingRecord"; + private static final String API_WAITLIST_BOOKING = "/GetRoomBookingWaitList"; + private static final String API_CHECK_SECOND_ROOM_TPD = "/GetMultiRoomBookingQualificationStatus"; + private static final String API_CHECK_APPROVER = "/CheckApprover"; + private static final String API_WAITLIST_DATA = "/GetWaitlistData"; + private static final String API_GET_ALL_PLAYER_PROFILE = "/GetPlayerInfo"; + private static final String API_GET_TODO_DASHBOARD = "/GetDashboardData"; + private static final String API_GET_TODO_DETAIL = "/GetTodolistDetails"; + private static final String API_GET_APPROVER_DATA="/RequestWaitlistData"; + private static final String API_GET_APPROVER="/RequestRoomBookingApprovalRouting"; + private static final String API_GET_TODO_LIST = "/GetTodolist"; + + + public HttpResponseResult invokeGetPlayerProfile( + String playerId, + String userId) throws Exception { + HttpResponseResult result; + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap<>(); + String token = getAccessToken(); + requestHeader.put("Authorization", token); + requestHeader.put("PlayerId", playerId); + requestHeader.put("UserId", userId); + + requestObj.put("playerId", playerId); + requestObj.put("userId", userId); + result = this.invokeESBAPI(ESB_Server, API_GET_PLAYER_PROFILE, requestObj, "GET", requestHeader); + return result; + } + + public HttpResponseResult invokeGetAllPlayerProfile(String playerId) throws Exception { + HttpResponseResult result; + String apiLink = SysCommon.mgmApiMockup ? API_GET_PLAYER_PROFILE : API_GET_ALL_PLAYER_PROFILE; + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap<>(); + String token = getAccessToken(); + requestHeader.put("Authorization", token); + requestHeader.put("PlayerId", playerId); + + requestObj.put("playerId", playerId); + result = this.invokeESBAPI(ESB_Server, apiLink, requestObj, "GET", requestHeader); + return result; + } + + public HttpResponseResult invokeCheckPlayerTPD( + String playerId, + String roomCate, + List dates, + String bookingType, + String property) throws Exception { + HttpResponseResult result; + String apiLink = API_CHECK_PLAYER_TPD; + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap<>(); + String token = getAccessToken(); + requestHeader.put("Authorization", token); + requestHeader.put("PlayerId", playerId); + requestHeader.put("RoomCategory", roomCate); + requestHeader.put("BookingType", bookingType); + requestHeader.put("Property", property); + requestHeader.put("StartDate", dates.getFirst()); + requestHeader.put("EndDate", dates.getLast()); + + requestObj.put("playerId", playerId); + requestObj.put("roomCategory", roomCate); + requestObj.put("startDate", dates.getFirst()); + requestObj.put("endDate", dates.getLast()); + result = this.invokeESBAPI(ESB_Server, apiLink, requestObj, "GET", requestHeader, 1); + return result; + } + + public HttpResponseResult invokeGetApprover(String playerId,String bookingType,String property,String roomCategory,String checkInDate,String checkOutDate,String userId) throws Exception { + HttpResponseResult result = null; + String apiLink =API_GET_APPROVER; + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap(); + String token = getAccessToken(); + requestHeader.put("Authorization", token); + requestObj.put("PlayerId", playerId); + requestObj.put("BookingType", bookingType); + requestObj.put("Property", property); + requestObj.put("RoomCategory", roomCategory); + requestObj.put("StartDate", checkInDate); + requestObj.put("EndDate", checkOutDate); + requestObj.put("UserId", userId); + + + result = this.invokeESBAPI(ESB_Server, apiLink, requestObj, "POST", requestHeader); + return result; + } + + public HttpResponseResult invokeGetApprovalData(String bookingId) throws Exception { + HttpResponseResult result = null; + String apiLink =API_GET_APPROVER_DATA; + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap(); + String token = getAccessToken(); + requestHeader.put("Authorization", token); + + requestObj.put("BookingId", bookingId); + + result = this.invokeESBAPI(ESB_Server, apiLink, requestObj, "POST", requestHeader); + return result; + } + + public HttpResponseResult invokeCheckApprover( + String userId, + String userName, + String roomType, + String property) throws Exception { + HttpResponseResult result; + String apiLink = API_CHECK_APPROVER; + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap<>(); + String token = getAccessToken(); + requestHeader.put("Authorization", token); + + if (!StringUtils.isEmpty(userId)) { + requestObj.put("UserId", userId); + } + if (!StringUtils.isEmpty(userName)) { + requestObj.put("UserName", userName); + } + requestObj.put("RoomCategory", roomType); + requestObj.put("Property", property); + result = this.invokeESBAPI(ESB_Server, apiLink, requestObj, "POST", requestHeader); + return result; + } + + public HttpResponseResult invokeGetUserInfo(String userId, String userName) throws Exception { + HttpResponseResult result; + String apiLink = API_GET_USER_INFO; + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap<>(); + String token = getAccessToken(); + requestHeader.put("Authorization", token); + if (!StringUtils.isEmpty(userId)) { + requestHeader.put("UserId", userId); + requestObj.put("userId", userId); + } + if (!StringUtils.isEmpty(userName)) { + requestHeader.put("UserName", userName); + requestObj.put("userName", userName); + } + + result = this.invokeESBAPI(ESB_Server, apiLink, requestObj, "GET", requestHeader); + return result; + } + + public HttpResponseResult invokeNonMGMBooking(String playerId) throws Exception { + HttpResponseResult result; + String apiLink = API_NON_MGM_BOOKING; + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap<>(); + String token = getAccessToken(); + requestHeader.put("Authorization", token); + requestHeader.put("PlayerId", playerId); + + requestObj.put("playerId", playerId); + result = this.invokeESBAPI(ESB_Server, apiLink, requestObj, "GET", requestHeader); + return result; + } + + public HttpResponseResult invokeWaitlistBooking(String playerId) throws Exception { + HttpResponseResult result; + String apiLink = API_WAITLIST_BOOKING; + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap<>(); + String token = getAccessToken(); + requestHeader.put("Authorization", token); + requestHeader.put("PlayerId", playerId); + + result = this.invokeESBAPI(ESB_Server, apiLink, requestObj, "GET", requestHeader); + return result; + } + + public HttpResponseResult invokeWaitlistData(String bookIds, int categoryType) throws Exception { + HttpResponseResult result; + String apiLink = API_WAITLIST_DATA; + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap<>(); + String token = getAccessToken(); + requestHeader.put("Authorization", token); + + requestObj.put("BookingId", bookIds); + result = this.invokeESBAPI(ESB_Server, apiLink, requestObj, "POST", requestHeader, categoryType); + return result; + } + + public HttpResponseResult invokeCheckPlayerSecondTPD( + String playerId, + String roomCate, + List dateRange, + String bookingType, + String property) throws Exception { + HttpResponseResult result; + String apiLink = API_CHECK_SECOND_ROOM_TPD; + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap<>(); + String token = getAccessToken(); + requestHeader.put("Authorization", token); + + requestObj.put("PlayerId", playerId); + requestObj.put("RoomCategory", roomCate); + requestObj.put("BookingType", bookingType); + requestObj.put("Property", property); + requestObj.put("DateRange", dateRange); + result = this.invokeESBAPI(ESB_Server, apiLink, requestObj, "POST", requestHeader); + return result; + } + + public String getAccessToken() throws Exception { + String token = ESB_ACCESS_TOKEN; + if (SysCommon.mgmApiMockup) return token; + ESB_APP_ID = SysCommon.apiConfig.getApiKey_ESB(); + ESB_APP_SECRET = SysCommon.apiConfig.getApiSecret_ESB(); + ESB_Server = SysCommon.apiConfig.getServerUrl_ESB(); + if (token == null || ESB_EXPIRED_TIME.getTime() < new Date().getTime()) { + String apiLink = API_GET_ACCESS_TOKEN; + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap<>(); + requestObj.put("AppId", ESB_APP_ID); + requestObj.put("AppSecret", ESB_APP_SECRET); + HttpResponseResult result = this.invokeESBAPI(ESB_Server, apiLink, requestObj, "POST", requestHeader); + if (result.getStatusCode() == 200) { + JSONObject resultObj = JSONObject.parseObject(result.getResponseContent()); + String status = resultObj.getString("StatusCode"); + if (Strings.CS.equals("OK", status)) { + token = resultObj.getString("Token"); + ESB_EXPIRED_TIME = DateTimeUtil.getDateFromString(resultObj.getString("ExpireTime"), "yyyy-MM-dd HH:mm:ss"); + ESB_ACCESS_TOKEN = token; + } else { + token = null; + ESB_ACCESS_TOKEN = null; + ESB_EXPIRED_TIME = new Date(); + } + } + } + return token; + } + + public HttpResponseResult invokeGetTodoDashboard( + String userId, + int categoryType) throws Exception { + HttpResponseResult result; + String apiLink = API_GET_TODO_DASHBOARD; + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap<>(); + String token = getAccessToken(); + requestHeader.put("Authorization", token); + + requestObj.put("UserId", userId); + result = this.invokeESBAPI(ESB_Server, apiLink, requestObj, "POST", requestHeader, categoryType); + return result; + } + + public HttpResponseResult invokeGetTodoDetail( + String playerId, + String todoCategory, + String todoSegment, + String date, + int categoryType) throws Exception { + HttpResponseResult result; + String apiLink = API_GET_TODO_DETAIL; + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap<>(); + String token = getAccessToken(); + requestHeader.put("Authorization", token); + + requestObj.put("PlayerId", playerId); + requestObj.put("TodoCategory", todoCategory); + requestObj.put("TodoSegment", todoSegment); + requestObj.put("Date", date); + + result = this.invokeESBAPI(ESB_Server, apiLink, requestObj, "POST", requestHeader, categoryType); + return result; + } + + public HttpResponseResult invokeGetTodoList( + String userId, + String category, + String type, + Date startDate, + Date endDate, + int categoryType) throws Exception { + HttpResponseResult result; + String apiLink = API_GET_TODO_LIST; + JSONObject requestObj = new JSONObject(); + Map requestHeader = new HashMap<>(); + String token = getAccessToken(); + requestHeader.put("Authorization", token); + + requestObj.put("UserId", userId); + requestObj.put("TodoCategory", category); + requestObj.put("TodoSegment", type); + requestObj.put("StartDate", startDate); + requestObj.put("EndDate", endDate); + + result = this.invokeESBAPI(ESB_Server, apiLink, requestObj, "POST", requestHeader, categoryType); + return result; + } + + // 如果不设置type,默认call opera + public HttpResponseResult invokeESBAPI( + String serverType, + String requestLink, + JSONObject requestContent, + String requestMethod, + Map requestHeader) throws Exception { + return invokeESBAPI(serverType, requestLink, requestContent, requestMethod, requestHeader, 0); + } + + /** + * + * @param serverType n + * @param requestLink n + * @param requestContent n + * @param requestMethod n + * @param requestHeader n + * @param type 0 - opera, 1 - daylight + * @return n + * @throws Exception e + */ + public HttpResponseResult invokeESBAPI( + String serverType, + String requestLink, + JSONObject requestContent, + String requestMethod, + Map requestHeader, + int type) throws Exception { + String serverUrl; + int timeoutTime; + if (Strings.CS.equals(serverType, ESB_Server)) { + serverUrl = SysCommon.apiConfig.getServerUrl_ESB(); + timeoutTime = SysCommon.apiConfig.getTimeout_ESB(); + } else { + throw new Exception("Invalid server type"); + } + + if (type == 1) { + requestLink = "/Daylight" + requestLink; + } + + HttpRequestDefine requestDef = new HttpRequestDefine(); + 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(); + Date endTime; + LogUtil.info(MGMApiService.class, "[invokeESBAPI] start request:"); + HttpResponseResult httpResult = + SysCommon.mgmApiMockup ? + HttpUtilMockup.processHttpRequest(requestDef) : + HttpUtil.processHttpRequest(requestDef); + httpResult.setRequestContent(requestDef.getEntityContent()); + //RefreshEndTime + endTime = new Date(); + //Get Spend Time + Gson gson = new Gson(); + spanTime = DateTimeUtil.getTimeSpanSSS(startTime, endTime); + LogUtil.info(MGMApiService.class, "[invokeESBAPI]getRequestUrl:" + gson.toJson(requestDef.getRequestUrl())); + LogUtil.info(MGMApiService.class, "[invokeESBAPI]getHeaders:" + gson.toJson(requestDef.getHeaders())); + LogUtil.info(MGMApiService.class, "[invokeESBAPI]getRequestMethod:" + gson.toJson(requestDef.getRequestMethod())); + LogUtil.info(MGMApiService.class, "[invokeESBAPI]getEntityContent:" + gson.toJson(requestContent)); + LogUtil.info(MGMApiService.class, "[invokeESBAPI]getStatusCode:" + gson.toJson(httpResult.getStatusCode())); + LogUtil.info(MGMApiService.class, "[invokeESBAPI]getErrorMessage:" + gson.toJson(httpResult.getErrorMessage())); + LogUtil.info(MGMApiService.class, "[invokeESBAPI]getResponseContent:" + gson.toJson(httpResult.getResponseContent())); + //Log Spend Time + LogUtil.info(MGMApiService.class, "[invokeESBAPI]SpendTime:" + spanTime + "ms"); + return httpResult; + } +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/common/services/SysServerStateService.java b/src/main/java/com/mgm/mcrm/common/services/SysServerStateService.java new file mode 100644 index 0000000..4981858 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/services/SysServerStateService.java @@ -0,0 +1,30 @@ +package com.mgm.mcrm.common.services; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.jms.AppControlMsgSender; +import com.mgm.mcrm.common.dtos.msg.AppSettingMsgData; +import com.mgm.mcrm.common.dtos.system.AppServerState; + +@Service +public class SysServerStateService { + + @Autowired + private AppControlMsgSender ctrlMsgSender; + + public void updateCfgByRequest(AppSettingMsgData updateRequest) { + AppServerState updServerInfo = SysCommon.updateCfgByRequest(updateRequest); + if(ctrlMsgSender!=null) { + SysCommon.jmsRunning = SysCommon.jmsRunning || ctrlMsgSender.sendMessage("SYNC_SERVER_STATE", updServerInfo); + } + } + + public void notifyCurrentState() { + AppServerState serverState = SysCommon.refreshAppServerState(); + if(ctrlMsgSender!=null) { + SysCommon.jmsRunning = SysCommon.jmsRunning || ctrlMsgSender.sendMessage("SYNC_SERVER_STATE",serverState); + } + } +} diff --git a/src/main/java/com/mgm/mcrm/common/utils/ADFSUtil.java b/src/main/java/com/mgm/mcrm/common/utils/ADFSUtil.java new file mode 100644 index 0000000..149b1f8 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/utils/ADFSUtil.java @@ -0,0 +1,185 @@ +package com.mgm.mcrm.common.utils; + +import java.io.ByteArrayOutputStream; +import java.io.StringReader; +import java.util.Base64; +import java.util.List; +import java.util.zip.Inflater; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import com.mgm.mcrm.authorization.dtos.LoginUserInfo; +import com.mgm.mcrm.authorization.models.SysUserView; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.interfaces.DecodedJWT; + + +public class ADFSUtil { + + public static LoginUserInfo parseUserFromXML(String xmlResponse) { + LoginUserInfo result=null; + try { + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); + InputSource inputSource = new InputSource(); + inputSource.setCharacterStream(new StringReader(xmlResponse)); + Document doc = dBuilder.parse(inputSource); + NodeList successNodes = doc.getElementsByTagName("Assertion"); + if(successNodes!=null&&successNodes.getLength()>0) { + result = new LoginUserInfo(); + result.setId((long) -1); + for (int i = 0; i < successNodes.getLength(); i++) { + Element subjectElement = (Element) successNodes.item(i); + String nameId=getSingleNodeTextByName(subjectElement,"NameID",null,null); + if(StringUtils.isNotBlank(nameId)) { + result.setLoginId(nameId); + } + String userName=getSingleNodeTextByName(subjectElement,"Attribute","Name","claims/name"); + if(StringUtils.isNotBlank(userName)) { + result.setDisplayName(userName); + } + String groupName=getSingleNodeTextByName(subjectElement,"Attribute","Name","claims/Group"); + if(StringUtils.isNotBlank(groupName)) { + result.setGroupName(groupName); + } + } + } + }catch(Exception err) { + result =null; + LogUtil.error(ADFSUtil.class, "Parse ADFS Result failed:"+err.getMessage()); + } + return result; + } + + public static byte[] copyArray(byte[] original, int newLength) { + byte[] copy = new byte[newLength]; + System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); + return copy; + } + + private static String getSingleNodeTextByName(Element parent, String tagName, String attrName, String attrValue) { + String result =null; + try { + NodeList dataNodes = parent.getElementsByTagName(tagName); + if (dataNodes!=null && dataNodes.getLength() > 0) { + if(StringUtils.isNotBlank(attrName)) { + for(int i=0;i0) { + result=""; + for(int j=0;j groupNames = decodeData.getClaim("user_group").asList(String.class); + String groupNameVal = ""; + for(int i=0;i0?";":"")+groupNames.get(i); + } + result.setGroupName(groupNameVal); + }catch(Exception err) { + result.setGroupName(decodeData.getClaim("user_group").asString()); + } + } + }catch(Exception err) { + LogUtil.error(ADFSUtil.class, "JWT ADFS Token:"+err.getMessage()); + } + return result; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/utils/AESUtil.java b/src/main/java/com/mgm/mcrm/common/utils/AESUtil.java new file mode 100644 index 0000000..14b3157 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/utils/AESUtil.java @@ -0,0 +1,155 @@ +package com.mgm.mcrm.common.utils; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Base64; +import java.util.Map; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.SecureRandom; + +import com.alibaba.fastjson.JSONObject; + +public class AESUtil { + + private static final String AES = "AES"; + private static final int GCM_IV_LENGTH = 12; // GCM推荐使用12字节的IV + private static final int GCM_TAG_LENGTH = 16; // GCM认证标签长度(128位) + + private static java.util.Base64.Encoder base64Encoder = java.util.Base64.getEncoder(); + private static java.util.Base64.Decoder base64Decoder = java.util.Base64.getDecoder(); + + static { + java.security.Security.setProperty("crypto.policy", "unlimited"); + removeCryptographyRestrictions(); + } + + public static void removeCryptographyRestrictions() { + try { + /* + * Do the following, but with reflection to bypass access checks: + * JceSecurity.isRestricted = false; + * JceSecurity.defaultPolicy.perms.clear(); + * JceSecurity.defaultPolicy.add(CryptoAllPermission.INSTANCE); + */ + final Class jceSecurity = Class.forName("javax.crypto.JceSecurity"); + final Class cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions"); + final Class cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission"); + + final Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted"); + isRestrictedField.setAccessible(true); + // 去除isRestricted的final限制 + final Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.setInt(isRestrictedField, isRestrictedField.getModifiers() & ~Modifier.FINAL); + isRestrictedField.set(null, false); + + final Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy"); + defaultPolicyField.setAccessible(true); + final PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null); + + final Field perms = cryptoPermissions.getDeclaredField("perms"); + perms.setAccessible(true); + ((Map) perms.get(defaultPolicy)).clear(); + + final Field instance = cryptoAllPermission.getDeclaredField("INSTANCE"); + instance.setAccessible(true); + defaultPolicy.add((Permission) instance.get(null)); + + } catch (final Exception e) { + e.printStackTrace(); + } + } + + public static SecretKey generateKey() throws Exception { + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(256); + return keyGen.generateKey(); + } + public static SecretKey stringToSecretKey(String keyString) { + byte[] keyBytes = base64Decoder.decode(keyString); + return new SecretKeySpec(keyBytes, AES); + } + public static String secretKeyToString(SecretKey secretKey) { + byte[] keyBytes = secretKey.getEncoded(); + return base64Encoder.encodeToString(keyBytes); + } + /** + * AES加密 + */ + public static String AES256Encrypt(String key, String content) { + try { + SecretKey secretKey = stringToSecretKey(key); + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + byte[] iv = new byte[GCM_IV_LENGTH]; + SecureRandom secureRandom = new SecureRandom(); + secureRandom.nextBytes(iv); // 生成随机的IV + GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv); + cipher.init(Cipher.ENCRYPT_MODE, secretKey, spec); + + byte[] ciphertext = cipher.doFinal(content.getBytes()); + byte[] encryptedData = new byte[iv.length + ciphertext.length]; + System.arraycopy(iv, 0, encryptedData, 0, iv.length); + System.arraycopy(ciphertext, 0, encryptedData, iv.length, ciphertext.length); + return base64Encoder.encodeToString(encryptedData); + + } catch (Exception e) { + //e.printStackTrace(); + } + return null; + } + /** + * AES解密 + */ + public static String AES256Decrypt(String key, String content) { + try { + SecretKey secretKey = stringToSecretKey(key); + byte[] encryptedData = base64Decoder.decode(content); + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + // 从加密数据中提取IV + byte[] iv = new byte[GCM_IV_LENGTH]; + System.arraycopy(encryptedData, 0, iv, 0, iv.length); + + GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv); + cipher.init(Cipher.DECRYPT_MODE, secretKey, spec); + + // 解密数据 + byte[] ciphertext = new byte[encryptedData.length - GCM_IV_LENGTH]; + System.arraycopy(encryptedData, GCM_IV_LENGTH, ciphertext, 0, ciphertext.length); + byte[] byteDecode = cipher.doFinal(ciphertext); + return new String(byteDecode, java.nio.charset.StandardCharsets.UTF_8); + } catch (Exception e) { + //e.printStackTrace(); + } + return null; + } + + public static String sha256(String plainString) { + String cipherString = null; + try { + // 获取实例(SHA-512同理) + MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); + // 计算摘要 + byte[] cipherBytes = messageDigest.digest(plainString.getBytes(StandardCharsets.UTF_8)); + // 输出为16进制字符串 + StringBuilder sb = new StringBuilder(); + for (byte b : cipherBytes) { + sb.append(String.format("%02x", b)); + } + cipherString = sb.toString(); + } catch (Exception e) { + e.printStackTrace(); + } + return cipherString; + } + +} diff --git a/src/main/java/com/mgm/mcrm/common/utils/DaoUtil.java b/src/main/java/com/mgm/mcrm/common/utils/DaoUtil.java new file mode 100644 index 0000000..cb30e9a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/utils/DaoUtil.java @@ -0,0 +1,86 @@ +package com.mgm.mcrm.common.utils; + +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.List; + +import jakarta.persistence.EntityManager; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.springframework.data.domain.Sort; +import org.springframework.data.domain.Sort.Direction; + + +@Getter +@Setter +public class DaoUtil { + + private static EntityManager entityManager; + public static final int BATCH_SIZE = 100; + + public static Sort buildSortByFilter(String orderInfo, String defaultSortProperty){ + Sort sort=null; + String sortColumn=""; + String sortProperties = StringUtils.isNotBlank(orderInfo)?orderInfo:defaultSortProperty; + Direction sortDirection = Direction.ASC; + if(StringUtils.isNotBlank(sortProperties)){ + String[] listSortProperty = sortProperties.split(";"); + for(int i=0;i1 && Strings.CI.equals("desc", sortInfos[1])) { + sortDirection = Direction.DESC; + } + if(sort==null) { + sort = Sort.by(sortDirection,sortColumn); + }else { + sort = sort.and(Sort.by(sortDirection,sortColumn)); + } + } + } + + } + return sort; + } + + + public static List parseMultipleFilter(String filerValues){ + List returnVals = new ArrayList(); + if(StringUtils.isNotBlank(filerValues)) { + String[] searchIds = filerValues.split(";"); + for(int i=0;i List parseMultipleFilter(String filerValues, Class valueType){ + List returnVals = new ArrayList(); + if(StringUtils.isNotBlank(filerValues)) { + Constructor classConstructor= null; + try { + classConstructor = valueType.getConstructor(String.class); + }catch(Exception err) { + classConstructor = null; + } + if(classConstructor!=null) { + String[] listSplitValues = filerValues.split(";"); + for(int i=0;i 12) { + return false; + } + + YearMonth yearMonth = YearMonth.of(year, month); + int maxDay = yearMonth.lengthOfMonth(); + + boolean isLeapYear = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); + if (month == 2 && isLeapYear) { + maxDay = 29; + } else if (month == 2) { + maxDay = 28; + } + + if (day < 1 || day > maxDay) { + return false; + } + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + LocalDate.parse(dateStr, formatter); + return true; + } catch (DateTimeParseException e) { + return false; + } + } + + public static Date getTodoYesterdayDay(String cutoffStartTime,String cutoffEndTime){ + String date = DateTimeUtil.getDateByFormat(new Date(), "yyyy-MM-dd"); + Date curentTime = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm"); + Date getStartTime = DateTimeUtil.getDateFromString(date+" "+cutoffStartTime, "yyyy-MM-dd HH:mm"); + Date getEndTime = DateTimeUtil.getDateFromString(date+" "+cutoffEndTime, "yyyy-MM-dd HH:mm"); + Date queryDate = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd"); + if(curentTime.getTime()>=getStartTime.getTime()&&curentTime.getTime()<=getEndTime.getTime()) { + queryDate = DateTimeUtil.addDay(queryDate, -1); + } + + return queryDate; + } + + /** + * OPERA cashier comment 入住日期段:英文 Mar 30,禁止 Date#toString()。 + * 单晚:30 Mar;同月多晚:30-31 Mar;跨月:30 Mar - 01 Apr + */ + public static String formatOperaCommentStayDateRange(Date checkin, Date checkout, Integer numOfNight) { + Locale en = Locale.ENGLISH; + if (checkin == null) { + return ""; + } + boolean stayIsSingleNight = Integer.valueOf(1).equals(numOfNight); + if (!stayIsSingleNight && numOfNight == null && checkout != null) { + stayIsSingleNight = "1".equals(getDiffDate(checkin, checkout, "day")); + } + if (stayIsSingleNight) { + return getDateByFormat(checkin, "dd MMM", en); + } + if (checkout == null) { + return getDateByFormat(checkin, "dd MMM", en); + } + Date lastNightDate = addDay(checkout, -1); + String firstMonthAbbr = getDateByFormat(checkin, "MMM", en); + String lastMonthAbbr = getDateByFormat(lastNightDate, "MMM", en); + String firstDayOfMonth = getDateByFormat(checkin, "dd", en); + String lastDayOfMonth = getDateByFormat(lastNightDate, "dd", en); + if (firstMonthAbbr != null && firstMonthAbbr.equals(lastMonthAbbr)) { + return firstDayOfMonth + "-" + lastDayOfMonth + " " + firstMonthAbbr; + } + return firstDayOfMonth + " " + firstMonthAbbr + " - " + lastDayOfMonth + " " + lastMonthAbbr; + } + + /** + * 按指定区域格式化日期(如 OPERA comment 需固定英文月份缩写 Mar/Apr)。 + */ + public static String getDateByFormat(Date dtDateTime, String strFormat, Locale locale) { + String returnDate = null; + if (dtDateTime != null && locale != null) { + try { + SimpleDateFormat formatter = new SimpleDateFormat(strFormat, locale); + returnDate = formatter.format(dtDateTime); + } catch (Exception err) { + + } + } + return returnDate; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/utils/ETLXstream.java b/src/main/java/com/mgm/mcrm/common/utils/ETLXstream.java new file mode 100644 index 0000000..92fddc3 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/utils/ETLXstream.java @@ -0,0 +1,24 @@ +package com.mgm.mcrm.common.utils; + +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.mapper.MapperWrapper; + +public class ETLXstream extends XStream { + protected MapperWrapper wrapMapper(MapperWrapper next) { + return new MapperWrapper(next) { + @Override + public boolean shouldSerializeMember(Class definedIn,String fieldName) { + // TODO Auto-generated method stub + //不能识别的节点 + if(definedIn==Object.class){ + return false; + } + if(fieldName.equals("fileName")){ + return false; + } + return super.shouldSerializeMember(definedIn, fieldName); + } + }; + + } +} diff --git a/src/main/java/com/mgm/mcrm/common/utils/EncryptUtil.java b/src/main/java/com/mgm/mcrm/common/utils/EncryptUtil.java new file mode 100644 index 0000000..0ee152a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/utils/EncryptUtil.java @@ -0,0 +1,31 @@ +package com.mgm.mcrm.common.utils; + + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; + +import org.springframework.util.DigestUtils; + + +public class EncryptUtil { + + public static String sha256(String plainString) { + String cipherString = null; + try { + // 获取实例(SHA-512同理) + MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); + // 计算摘要 + byte[] cipherBytes = messageDigest.digest(plainString.getBytes(StandardCharsets.UTF_8)); + // 输出为16进制字符串 + StringBuilder sb = new StringBuilder(); + for (byte b : cipherBytes) { + sb.append(String.format("%02x", b)); + } + cipherString = sb.toString(); + } catch (Exception e) { + e.printStackTrace(); + } + return cipherString; + } + + } diff --git a/src/main/java/com/mgm/mcrm/common/utils/ExcelUtils.java b/src/main/java/com/mgm/mcrm/common/utils/ExcelUtils.java new file mode 100644 index 0000000..56a0756 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/utils/ExcelUtils.java @@ -0,0 +1,931 @@ +package com.mgm.mcrm.common.utils; + +import java.awt.Color; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.text.SimpleDateFormat; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.UUID; + +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.apache.commons.text.StringEscapeUtils; +import org.apache.poi.hssf.usermodel.HSSFDataFormat; +import org.apache.poi.ss.usermodel.BuiltinFormats; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.usermodel.DefaultIndexedColorMap; +import org.apache.poi.xssf.usermodel.XSSFCell; +import org.apache.poi.xssf.usermodel.XSSFCellStyle; +import org.apache.poi.xssf.usermodel.XSSFColor; +import org.apache.poi.xssf.usermodel.XSSFDataFormat; +import org.apache.poi.xssf.usermodel.XSSFFont; +import org.apache.poi.xssf.usermodel.XSSFRichTextString; +import org.apache.poi.xssf.usermodel.XSSFRow; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.web.multipart.MultipartFile; + +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.parser.Feature; + +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.dtos.excel_model.ColumnDefine; +import com.mgm.mcrm.common.dtos.excel_model.ColumnGroupInfo; +import com.mgm.mcrm.common.dtos.excel_model.DataBlock; +import com.mgm.mcrm.common.dtos.excel_model.ExportDefine; +import com.mgm.mcrm.common.dtos.excel_model.GroupItem; +import com.mgm.mcrm.common.dtos.excel_model.ImportDefine; +import com.mgm.mcrm.common.dtos.excel_model.RowFieldInfo; +import com.mgm.mcrm.common.dtos.excel_model.SheetDefine; +import com.mgm.mcrm.common.dtos.system.ResFileResult; + + +public class ExcelUtils { + public static final int TEXT_ELEMENT =1; + public static final int DATABLOCK_ELEMENT =2; + private static int customFormatIndex = 100; + private static final DateTimeFormatter msecondFormat = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS").withZone(ZoneOffset.ofHours(8)); + private static Random rnd = new Random(); + private static Map importDefines = new HashMap(); + private static Map exportDefines = new HashMap(); + + public static void loadExcelDefines() { + try { + File directory = new File(SysCommon.runtime_path + "/"+SysCommon.runtimeName+"/excel_define/import/"); + String[] fileNames = directory.list(); + if (fileNames != null) { + for (String fileName : fileNames) { + if(Strings.CI.endsWith(fileName, ".json")) { + String content = SysCommon.loadResFileContentByPath("/excel_define/import/"+fileName, 2); + ImportDefine defineObject = null; + try { + defineObject = JSONObject.parseObject(content, ImportDefine.class,Feature.SupportNonPublicField,Feature.IgnoreNotMatch); + if(defineObject!=null && StringUtils.isNotBlank(defineObject.getImportName())) { + importDefines.put(defineObject.getImportName(), defineObject); + } + }catch(Exception err) { + LogUtil.error(ExcelUtils.class, "Parse import define failed with error:"+err.getMessage()); + } + } + } + } + }catch (Exception err) { + LogUtil.error(ExcelUtils.class, "Load import define failed with error:"+err.getMessage()); + } + try { + File directory = new File(SysCommon.runtime_path + "/"+SysCommon.runtimeName+"/excel_define/export/"); + String[] fileNames = directory.list(); + if (fileNames != null) { + for (String fileName : fileNames) { + if(Strings.CI.endsWith(fileName, ".json")) { + String content = SysCommon.loadResFileContentByPath("/excel_define/export/"+fileName, 2); + ExportDefine defineObject = null; + try { + defineObject = JSONObject.parseObject(content, ExportDefine.class,Feature.SupportNonPublicField,Feature.IgnoreNotMatch); + if(defineObject!=null && StringUtils.isNotBlank(defineObject.getExportName())) { + exportDefines.put(defineObject.getExportName(), defineObject); + } + }catch(Exception err) { + LogUtil.error(ExcelUtils.class, "Parse export define failed with error:"+err.getMessage()); + } + } + } + } + }catch (Exception err) { + LogUtil.error(ExcelUtils.class, "Load export define failed with error:"+err.getMessage()); + } + } + + public static ImportDefine getImportDefineByName(String importName) { + ImportDefine importDef = null; + if(importDefines.containsKey(importName)) { + importDef = importDefines.get(importName); + } + return importDef; + } + + public static ExportDefine getExportDefineByName(String exportName) { + ExportDefine exportDef = null; + if(exportDefines.containsKey(exportName)) { + exportDef = exportDefines.get(exportName); + } + return exportDef; + } + + public static BaseApiResponse> importDataBlock(ImportDefine importDef, String importFileName, Map> groupInfo) { + BaseApiResponse> processResult = new BaseApiResponse<>(); + processResult.setSuccess(true); + List resultData = new ArrayList<>(); + try { + FileInputStream excelFile = new FileInputStream(importFileName); + XSSFWorkbook wbook = new XSSFWorkbook(excelFile); + List pageDefs = importDef.getImportPages(); + if(pageDefs!=null) { + for(SheetDefine sheetDef:pageDefs) { + XSSFSheet sheet=null; + if(StringUtils.isNotBlank(sheetDef.getSheetName())) { + sheet = wbook.getSheet(sheetDef.getSheetName()); + }else { + sheet = wbook.getSheetAt(sheetDef.getSheetIndx()); + } + if(sheet==null) { + processResult.setSuccess(false); + String errorMsg = "Data Sheet "+sheetDef.getSheetIndx() + +(StringUtils.isNotBlank(sheetDef.getSheetName())?" ["+sheetDef.getSheetName()+"]":"")+" not found"; + processResult.setMessage(errorMsg); + break; + }else { + if(sheetDef.getDataElements()!=null) { + int lastRow=0; + int lastCol=0; + for(DataBlock dataBlock:sheetDef.getDataElements()) { + List masterFields = new ArrayList(); + List groupList = new ArrayList(); + List colDefs = dataBlock.getColumnDefs(); + Class objClass = null; + if(StringUtils.isNotBlank(dataBlock.getObjClassName())) { + try { + objClass = Class.forName(dataBlock.getObjClassName()); + }catch(Exception err) { + LogUtil.error(ExcelUtils.class, "Get import data class error:"+err.getMessage()); + } + } + int colIdx =0; + for(int k=0; k objGroupDataClass = null; + if(StringUtils.isNotBlank(colDef.getDataType())) { + try { + objGroupDataClass = Class.forName(colDef.getDataType()); + }catch(Exception err) { + LogUtil.error(ExcelUtils.class, "Get import group data class error:"+err.getMessage()); + } + } + if(objGroupDataClass!=null && StringUtils.isNotBlank(colDef.getGroupKeyAttrName())) { + try { + keyAttrField = objGroupDataClass.getDeclaredField(colDef.getGroupKeyAttrName()); + keyAttrField.setAccessible(true); + }catch(Exception err) { + keyAttrField = null; + LogUtil.error(ExcelUtils.class, "Get Import group key Field Define Error:"+err.getMessage()); + } + } + //-- + List groupColDefs = colDef.getGroupColumns(); + List groupColumns = new ArrayList(); + for(ColumnDefine gColDef:groupColDefs) { + RowFieldInfo gField = getImportFieldInfoFromDefine(gColDef,objGroupDataClass); + groupColumns.add(gField); + } + //-- + colGroup.setGroupColumns(groupColumns); + colGroup.setGroupDataType(objGroupDataClass); + colGroup.setKeyField(keyAttrField); + colGroup.setColStartIndex(colIdx); + if(groupInfo.containsKey(colDef.getGroupName())) { + List groupItems = groupInfo.get(colDef.getGroupName()); + List sortGroupItems = new ArrayList(); + Row headerRow = sheet.getRow(lastRow+groupItems.getFirst().getHeaderIndex()); + for(int m=0;m=0?dataBlock.getOffsetRow():lastRow-dataBlock.getOffsetRow(); + int cCol=dataBlock.getOffsetCol()>=0?dataBlock.getOffsetCol():lastCol-dataBlock.getOffsetCol(); + List blockResult = parseImportDataBlock(sheet,objClass, masterFields,groupList,cRow,cCol); + resultData.add(blockResult); + }else { + processResult.setSuccess(false); + processResult.setCode(validateCode); + processResult.setMessage("Invalid Import Template"); + break; + } + } + } + } + if(!processResult.isSuccess()) { + break; + } + } + processResult.setData(resultData); + } + }catch(Exception err) { + processResult.setSuccess(false); + processResult.setCode("-1"); + processResult.setMessage(err.getMessage()); + } + return processResult; + } + + private static String validateBlockTemplate(XSSFSheet sheet,List masterFields,List groupList, int lastBlockRowEnd, int lastBlockColEnd) { + String errCode = ""; + for(int i=0;i0) { + for(int i=0;i gItems = colGroup.getGroupItems(); + for(int j=0;j parseImportDataBlock(XSSFSheet sheet,Class objClass, List masterFields,List groupList,int cRow, int cCol) throws InstantiationException, IllegalAccessException{ + List parseResult = new ArrayList(); + //-- + int maxDataRow = sheet.getLastRowNum(); + String[] dataRow=null; + Object dataRowObj=null; + boolean isEnd=false; + while(isEnd==false) { + boolean isEmptyRow=true; + if(objClass==null) { + dataRow= new String[masterFields.size()]; + }else { + dataRowObj = objClass.newInstance(); + } + Row curRow = sheet.getRow(cRow); + if(curRow!=null) { + for(int i=0; i0) { + for(ColumnGroupInfo groupInfo:groupList) { + List gFields = groupInfo.getGroupColumns(); + List gItems = groupInfo.getGroupItems(); + List groupData = new ArrayList(); + for(int i=0;i= maxDataRow) { + isEnd=true; + } + cRow++; + } + //-- + return parseResult; + } + + //-- + public static String getCellTextValueInRow(Row row, int colIndex, boolean isAutoDetect) { + String cellValue = ""; + if (row != null) { + Cell cell = row.getCell(colIndex); + if (cell != null) { + if(isAutoDetect==false) { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd"); + Date dateVal = DateUtil.getJavaDate(cell.getNumericCellValue()); + if(dateVal!=null) + cellValue = dateFormat.format(dateVal); + else + cellValue=""; + }else { + if (cell.getCellType().equals(CellType.BOOLEAN)) { + cellValue = String.valueOf(cell.getBooleanCellValue()); + } else if (cell.getCellType().equals(CellType.NUMERIC)) { + + double cellNumValue = cell.getNumericCellValue(); + // --如果是整數則去掉後面的位數轉成整數 + if (Math.floor(cellNumValue) == cellNumValue) { + cellValue = String.valueOf((int) Math.floor(cellNumValue)); + } else { + cellValue = String.valueOf(cell.getNumericCellValue()); + } + + } else { + cellValue = cell.getRichStringCellValue().getString(); + } + } + + } + } + return cellValue; + } + + private static RowFieldInfo getImportFieldInfoFromDefine(ColumnDefine colDef,Class masterClass) { + Field attrField = null; + RowFieldInfo colInfo= new RowFieldInfo(); + if(masterClass!=null && StringUtils.isNotBlank(colDef.getAttrName())) { + try { + attrField = masterClass.getDeclaredField(colDef.getAttrName()); + attrField.setAccessible(true); + }catch(Exception err) { + attrField = null; + LogUtil.error(ExcelUtils.class, "Get Field Define Error:"+err.getMessage()); + } + } + colInfo.setColumnHeader(colDef.getColumnHeader()); + colInfo.setHeaderRowIdx(colDef.getHeaderRowIdx()); + colInfo.setCheckHeader(colDef.isCheckHeader()); + colInfo.setDataField(attrField); + return colInfo; + } + + private static RowFieldInfo getFieldInfoFromDefine(ColumnDefine colDef,Class masterClass,XSSFCellStyle fieldStyle, XSSFCellStyle tStyle,XSSFDataFormat dataFormat) { + Field attrField = null; + RowFieldInfo colInfo= new RowFieldInfo(); + if(masterClass!=null && StringUtils.isNotBlank(colDef.getAttrName())) { + try { + attrField = masterClass.getDeclaredField(colDef.getAttrName()); + attrField.setAccessible(true); + }catch(Exception err) { + attrField = null; + LogUtil.error(ExcelUtils.class, "Get Field Define Error:"+err.getMessage()); + } + } + colInfo.setCheckHeader(colDef.isCheckHeader()); + colInfo.setDataField(attrField); + colInfo.setColumnHeader(colDef.getColumnHeader()); + colInfo.setHeaderRowIdx(colDef.getHeaderRowIdx()); + colInfo.setDateFormat(colDef.getFormatVal()); + colInfo.setDataType(colDef.getDataType()); + fieldStyle.cloneStyleFrom(tStyle); + fieldStyle.setDataFormat(getCellTextFormatByDataType(colDef.getFormatVal(),dataFormat)); + if(StringUtils.isNotBlank(colDef.getTextAlign())) { + String fa = colDef.getTextAlign(); + fieldStyle.setAlignment(Strings.CS.equals(fa, "center")?HorizontalAlignment.CENTER:(Strings.CS.equals(fa, "right")?HorizontalAlignment.RIGHT:HorizontalAlignment.LEFT)); + } + colInfo.setFieldStyle(fieldStyle); + return colInfo; + } + + public static File exportEXCEL(ExportDefine excelDef, Map> exportData, Map> groupInfo) throws Exception { + SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy"); + XSSFWorkbook wbook = new XSSFWorkbook(); + List pageDefs = excelDef.getExportPages(); + //-- + for(int i=0; i pageElements = pageDef.getDataElements(); + if(pageElements!=null) { + for(int j=0;j bData = exportData.get(dataDef.getBlockName()); + if(bData!=null&& !bData.isEmpty()) { + dataVal = String.valueOf(bData.getFirst()); + } + setCellText(getCell(wsheet,cRow,cCol),tStyle,dataVal,"String"); + if(colDef.getColumnWidth()>0) { + wsheet.setColumnWidth(cCol, colDef.getColumnWidth()*256); + } + cRow++; + cCol++; + } + + }else if(dataDef.getElementType()==ExcelUtils.DATABLOCK_ELEMENT) { + int startRow = cRow; + int startCol = cCol; + List colDefs = dataDef.getColumnDefs(); + Class objClass = null; + if(StringUtils.isNotBlank(dataDef.getObjClassName())) { + try { + objClass = Class.forName(dataDef.getObjClassName()); + }catch(Exception err) { + LogUtil.error(ExcelUtils.class, "Get export data class error:"+err.getMessage()); + } + } + List masterFields = new ArrayList(); + List groupList = new ArrayList(); + List fieldStyles = new ArrayList(); + int colIdx =0; + for(int k=0; k0) { + wsheet.setColumnWidth(startCol+colIdx, colDef.getColumnWidth()*256); + } + masterFields.add(colInfo); + colIdx++; + }else if(groupInfo!=null) { + ColumnGroupInfo colGroup = new ColumnGroupInfo(); + Field attrField = null; + Field keyAttrField=null; + if(objClass!=null && StringUtils.isNotBlank(colDef.getAttrName())) { + try { + attrField = objClass.getDeclaredField(colDef.getAttrName()); + attrField.setAccessible(true); + }catch(Exception err) { + attrField = null; + LogUtil.error(ExcelUtils.class, "Get export group Field Define Error:"+err.getMessage()); + } + } + colGroup.setGroupDataField(attrField); + Class objGroupDataClass = null; + if(StringUtils.isNotBlank(colDef.getDataType())) { + try { + objGroupDataClass = Class.forName(colDef.getDataType()); + }catch(Exception err) { + LogUtil.error(ExcelUtils.class, "Get export group data class error:"+err.getMessage()); + } + } + if(objGroupDataClass!=null && StringUtils.isNotBlank(colDef.getGroupKeyAttrName())) { + try { + keyAttrField = objGroupDataClass.getDeclaredField(colDef.getGroupKeyAttrName()); + keyAttrField.setAccessible(true); + }catch(Exception err) { + keyAttrField = null; + LogUtil.error(ExcelUtils.class, "Get export group key Field Define Error:"+err.getMessage()); + } + } + //-- + List groupColDefs = colDef.getGroupColumns(); + List groupColumns = new ArrayList(); + for(ColumnDefine gColDef:groupColDefs) { + RowFieldInfo gField = getFieldInfoFromDefine(gColDef,objGroupDataClass,wbook.createCellStyle(),tStyle,dataFormat); + groupColumns.add(gField); + } + //-- + colGroup.setGroupColumns(groupColumns); + colGroup.setGroupDataType(objGroupDataClass); + colGroup.setKeyField(keyAttrField); + colGroup.setColStartIndex(colIdx); + if(groupInfo.containsKey(colDef.getGroupName())) { + List groupItems = groupInfo.get(colDef.getGroupName()); + colGroup.setGroupItems(groupItems); + if(dataDef.isShowHeader()) { + for(int m=0;m=0) { + int gRow = gItem.getHeaderIndex(); + if(groupColumns.size()>1) { + CellRangeAddress groupHeaderMerge = new CellRangeAddress(startRow+gRow, startRow+gRow, startCol+colIdx+m*groupColumns.size(), startCol+colIdx+((m+1)*groupColumns.size()-1)); + wsheet.addMergedRegion(groupHeaderMerge); + } + setCellText(getCell(wsheet,startRow+gItem.getHeaderIndex(),startCol+colIdx+(m*groupColumns.size())),titleStyle,gItem.getItemText(),"String"); + } + if(groupColDefs!=null && groupColDefs.size()>0) { + for(int n=0;n bData = exportData.get(dataDef.getBlockName()); + int maxColIdx =0; + if(bData!=null) { + for(int k=0; k dataType = dataGroup.getGroupDataType(); + List groupDataList = null; + if(dataField!=null) { + try { + groupDataList = (List)dataField.get(colData); + }catch(Exception err) { + LogUtil.error(ExcelUtils.class, "Get Group Data error:"+err.getMessage()); + } + } + if(groupDataList!=null) { + for(int m=0;m gFields = dataGroup.getGroupColumns(); + for(int p=0;p> exportData,Map> groupKeys, HttpServletResponse response, HttpServletRequest request) throws Exception { + File file = ExcelUtils.exportEXCEL(reportDef,exportData,groupKeys); + response.reset(); + String basePath = SysCommon.runtime_path + "\\"+SysCommon.runtimeName+"\\tmp\\"; + String filePath = file.getCanonicalPath(); + basePath = basePath.replace("/", "\\"); + filePath = filePath.replace("/", "\\"); + if (!filePath.startsWith(basePath)) { + throw new SecurityException("Invalid file path"); + } + response.setHeader("Access-Control-Allow-Headers", "Content-Type"); + response.setHeader("Access-Control-Expose-Headers", "Location"); + response.setHeader("Access-Control-Expose-Headers", "content-disposition"); + response.setContentType("application/vnd.ms-excel; charset=utf-8"); + response.setHeader("content-disposition", + "attachment;filename=" + (StringUtils.isNotBlank(reportFileName)?reportFileName:reportDef.getExportFileName())); + response.getOutputStream().write(FileUtils.readFileToByteArray(file)); + ExcelUtils.clearTempFile(file.getName()); + } + public static void errorResponse(String errorMessage,HttpServletRequest request, HttpServletResponse response) throws Exception { + //response.setContentType("text/html"); + String returnMsg = StringEscapeUtils.escapeHtml4(errorMessage); + response.sendError(500, returnMsg); + } + //=========== + public static ExportDefine parseExportDefination(String jsonContent) { + ExportDefine exportDef = null; + try { + exportDef = JSONObject.parseObject(jsonContent,ExportDefine.class); + }catch(Exception err) { + LogUtil.error(ExcelUtils.class, "Parse Export Defination error:"+err.getMessage()); + } + return exportDef; + } + + public static SheetDefine parseExportSheet(String jsonContent) { + SheetDefine exportSheetDef = null; + try { + exportSheetDef = JSONObject.parseObject(jsonContent,SheetDefine.class); + }catch(Exception err) { + LogUtil.error(ExcelUtils.class, "Parse Export Sheet error:"+err.getMessage()); + } + return exportSheetDef; + } + + public static DataBlock parseDataElement(String jsonContent) { + DataBlock exportDateElementDef = null; + try { + exportDateElementDef = JSONObject.parseObject(jsonContent,DataBlock.class); + }catch(Exception err) { + LogUtil.error(ExcelUtils.class, "Parse Export Data Element error:"+err.getMessage()); + } + return exportDateElementDef; + } + + public static ResFileResult transTempFile(MultipartFile file) { + ResFileResult result = new ResFileResult(); + String originalFileName = ""; + try { + originalFileName = file.getOriginalFilename(); + String tmpFolderName =SysCommon.runtime_path+"/"+SysCommon.runtimeName+"/tmp"; + File resourceFolder = new File(tmpFolderName); + if(!resourceFolder.exists()) { + FileUtils.forceMkdir(resourceFolder); + } + Date currentTime = new Date(); + String tmpFileName = msecondFormat.format(currentTime.toInstant())+"_"+rnd.nextInt(1000)+".xlsx"; + String targetFileName = tmpFolderName+"/"+tmpFileName; + byte[] fileData = file.getBytes(); + FileOutputStream fio = new FileOutputStream(targetFileName); + fio.write(fileData); + fio.close(); + result.setSuccess(true); + result.setFileName(tmpFileName); + result.setFilePath(targetFileName); + }catch(Exception err) { + result.setSuccess(false); + LogUtil.error(ExcelUtils.class, "Read import file ["+originalFileName+"] error:"+ err.getMessage()); + } + return result; + } + public static void clearTempFile(String filePath) { + try { + String targetFileName = Strings.CI.startsWith(filePath, SysCommon.runtime_path)? + filePath:(SysCommon.runtime_path+"/"+SysCommon.runtimeName+"/tmp/"+filePath); + targetFileName = targetFileName.replace("\\", "/"); + while(targetFileName.indexOf("//")>=0) { + targetFileName = targetFileName.replace("//", "/"); + } + File resFile = new File(targetFileName); + if(resFile.exists()) { + resFile.delete(); + } + }catch(Exception ignored) { + + } + } + //=========== + private static XSSFCell getCell(XSSFSheet wsheet, int cRow, int cCol){ + XSSFCell cell = null; + XSSFRow row = wsheet.getRow(cRow); + if(row==null){ + row = wsheet.createRow(cRow); + } + cell = row.getCell(cCol); + if(cell==null){ + cell = row.createCell(cCol); + } + return cell; + } + + private static XSSFCell setCellText(XSSFCell cell, XSSFCellStyle cellStyle, String cellValue,String dataType){ + cell.setCellStyle(cellStyle); + if(Strings.CI.equals("Integer", dataType) || Strings.CI.equals("Double", dataType)) { + try { + double numVal = Double.parseDouble(cellValue); + cell.setCellValue(numVal); + }catch(Exception err) { + cell.setCellValue(new XSSFRichTextString(cellValue)); + } + }else { + cell.setCellValue(new XSSFRichTextString(cellValue)); + } + + return cell; + } + +} diff --git a/src/main/java/com/mgm/mcrm/common/utils/HttpUtil.java b/src/main/java/com/mgm/mcrm/common/utils/HttpUtil.java new file mode 100644 index 0000000..6f71b84 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/utils/HttpUtil.java @@ -0,0 +1,264 @@ +package com.mgm.mcrm.common.utils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.nio.charset.Charset; +import java.security.cert.X509Certificate; +import java.util.List; +import java.util.Map; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.security.cert.CertificateException; +import jakarta.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.apache.hc.client5.http.classic.methods.HttpDelete; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.classic.methods.HttpPut; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.cookie.Cookie; +import org.apache.hc.client5.http.cookie.CookieStore; +import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.client5.http.socket.ConnectionSocketFactory; +import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.client5.http.ssl.TrustAllStrategy; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.config.Registry; +import org.apache.hc.core5.http.config.RegistryBuilder; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.io.entity.StringEntity; +import org.apache.hc.core5.ssl.SSLContextBuilder; +import org.apache.hc.core5.util.Timeout; +import org.springframework.web.multipart.MultipartFile; + + + +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; + +public class HttpUtil { + + //----------- + public static HttpResponseResult processHttpRequest(HttpRequestDefine request) { + HttpResponseResult responseResult = new HttpResponseResult(); + CloseableHttpClient httpclient=null; + CloseableHttpResponse response = null; + String requestUrl =request.getRequestUrl(); + if(!NetworkUtil.isValidURL(requestUrl)){ + throw new SecurityException("Invalid URL of ["+requestUrl+"]"); + } + if (!SysCommon.isAllowApiServer(requestUrl)) { + throw new SecurityException("URL not allowed"); + } + requestUrl = NetworkUtil.encodePathWithSpring(requestUrl); + try { + //-- + RequestConfig.Builder configBuilder = RequestConfig.custom(); + configBuilder.setRedirectsEnabled(false); + if(request.getTimeout()>0) { + int timeout = request.getTimeout(); + configBuilder.setConnectionRequestTimeout(Timeout.ofMicroseconds(timeout)); + } + RequestConfig requestConfig = configBuilder.build(); + //-- + HttpClientBuilder clientBuilder = HttpClients.custom(); + if(Strings.CI.startsWith(requestUrl, "https://")) { + SSLContext sslContext = null; + try { + sslContext = SSLContextBuilder.create().loadTrustMaterial(TrustAllStrategy.INSTANCE).build(); + } catch (Exception e) { + e.printStackTrace(); + } + Registry registry = RegistryBuilder.create() + .register("https", new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE )) + .build(); + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry); + + HttpClientBuilder httpClientBuilder = HttpClients.custom().setConnectionManager(connectionManager) + .setDefaultRequestConfig(requestConfig); + if(request.getCredentials()!=null) { + httpClientBuilder.setDefaultCredentialsProvider(request.getCredentials()); + } + httpclient = httpClientBuilder.build(); + + }else { + if(request.getCredentials()!=null) { + clientBuilder.setDefaultCredentialsProvider(request.getCredentials()); + } + httpclient = clientBuilder.build(); + } + HttpClientContext context = HttpClientContext.create(); + //-- + if(Strings.CI.equals("POST", request.getRequestMethod())) { + HttpPost httppost = new HttpPost(requestUrl); + httppost.setConfig(requestConfig); + if(request.isUpload()!=true) { + if(request.getHeaders()!=null) { + Map headermap = request.getHeaders(); + for (Map.Entry entry : headermap.entrySet()) { + if(!Strings.CI.equals("Content-Length",entry.getKey())){ + httppost.addHeader(entry.getKey(), NetworkUtil.sanitizeHeaderValue(entry.getValue())); + } + } + } + httppost.setEntity(new StringEntity(request.getEntityContent(), Charset.forName("UTF-8"))); + responseResult.setRequestContent(request.getEntityContent()); + response = httpclient.execute(httppost,context); + }else { + MultipartFile processFile = request.getUploadFile(); + MultipartEntityBuilder builder = MultipartEntityBuilder.create(); + builder.addBinaryBody(request.getFileParaName(), processFile.getInputStream(), ContentType.MULTIPART_FORM_DATA, processFile.getName()); + HttpEntity entity = builder.build(); + httppost.setEntity(entity); + response = httpclient.execute(httppost,context); + } + + }else if(Strings.CI.equals("PUT", request.getRequestMethod())){ + HttpPut httpput = new HttpPut(requestUrl); + httpput.setConfig(requestConfig); + if(request.getHeaders()!=null) { + Map headermap = request.getHeaders(); + for (Map.Entry entry : headermap.entrySet()) { + if(!Strings.CI.equals("Content-Length",entry.getKey())){ + httpput.addHeader(entry.getKey(), NetworkUtil.sanitizeHeaderValue(entry.getValue())); + } + } + } + httpput.setEntity(new StringEntity(request.getEntityContent(), Charset.forName(request.getRequestCharSet()))); + responseResult.setRequestContent(request.getEntityContent()); + response = httpclient.execute(httpput); + }else if(Strings.CI.equals("DELETE", request.getRequestMethod())){ + HttpDelete httpdel = new HttpDelete(requestUrl); + httpdel.setConfig(requestConfig); + response = httpclient.execute(httpdel,context); + }else { + //-- Get + HttpGet httpget = new HttpGet(requestUrl); + httpget.setConfig(requestConfig); + if(request.getHeaders()!=null) { + Map headermap = request.getHeaders(); + for (Map.Entry entry : headermap.entrySet()) { + if(!Strings.CI.equals("Content-Length",entry.getKey())){ + httpget.addHeader(entry.getKey(), NetworkUtil.sanitizeHeaderValue(entry.getValue())); + } + } + } + response = httpclient.execute(httpget,context); + } + //-- + responseResult.setRequestUrl(requestUrl); + responseResult.setStatusCode(response.getCode()); + HttpEntity responseEntity = response.getEntity(); + if(responseEntity!=null) { + String responseBody = EntityUtils.toString(responseEntity, Charset.forName(request.getResponseCharSet())); + EntityUtils.consume(responseEntity); + responseResult.setResponseContent(responseBody); + } + + CookieStore cookieStore = context.getCookieStore(); + if(cookieStore!=null) { + List cookies = cookieStore.getCookies(); + responseResult.setCookies(cookies); + } + //-- + }catch(Exception err) { + responseResult.setStatusCode(-1); + responseResult.setMessage(err.getMessage()); + LogUtil.error(HttpUtil.class, "Request HTTP[URL:"+request.getRequestUrl()+"][Method:"+request.getRequestMethod()+"] error:"+err.getMessage()); + }finally { + try { + if(response!=null) { + response.close(); + } + }catch(Exception err) { + + } + try { + if(httpclient!=null) { + httpclient.close(); + } + }catch(Exception err) { + + } + } + return responseResult; + } + //----------- + public static SSLContext getSSLContext() { + try { + // 这里可以填两种值 TLS和LLS , 具体差别可以自行搜索 + SSLContext sc = SSLContext.getInstance("TLS"); + // 构建新对象 + X509TrustManager manager = new X509TrustManager() { + @Override + public void checkServerTrusted(X509Certificate[] chain, String arg1) throws CertificateException { + if (chain == null || chain.length == 0) { + throw new IllegalArgumentException("No server certificates provided"); + } + for (X509Certificate cert : chain) { + cert.checkValidity(); + } + } + + @Override + public void checkClientTrusted(X509Certificate[] chain, String arg1) throws CertificateException { + if (chain == null || chain.length == 0) { + throw new CertificateException("No client certificates provided"); + } + for (X509Certificate cert : chain) { + cert.checkValidity(); // 检查证书是否在有效期内 + } + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new java.security.cert.X509Certificate[] {}; + } + + }; + sc.init(null, new TrustManager[]{manager}, null); + return sc; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + + public static String readRequestBody(HttpServletRequest request) { + BufferedReader br = null; + StringBuilder sb = new StringBuilder(""); + try { + br = request.getReader(); + String str; + while ((str = br.readLine()) != null) { + sb.append(str); + } + br.close(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (null != br) { + try { + br.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return sb.toString(); + } +} diff --git a/src/main/java/com/mgm/mcrm/common/utils/LogUtil.java b/src/main/java/com/mgm/mcrm/common/utils/LogUtil.java new file mode 100644 index 0000000..0e9f733 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/utils/LogUtil.java @@ -0,0 +1,85 @@ +package com.mgm.mcrm.common.utils; + +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.fastjson.JSONObject; +import com.mgm.mcrm.common.constants.SysCommon; + +public class LogUtil { + private static String loggerName = LogUtil.class.getName(); + private static Logger logger = LoggerFactory.getLogger(loggerName); + + public static Logger getLogger(Class callClass){ + try + { + logger = LoggerFactory.getLogger(callClass.getName()); + }catch(Exception err){ + loggerName = LogUtil.class.getName(); + logger = LoggerFactory.getLogger(loggerName); + } + return logger; + } + + public static void info(Class callClass,String message) { + if(SysCommon.appDebugLog == true) + getLogger(callClass).info(message); + } + + public static void warn(Class callClass,String message) { + if(SysCommon.appDebugLog == true) + getLogger(callClass).warn(message); + } + + public static void error(Class callClass,String message) { + if(SysCommon.appDebugLog == true) + getLogger(callClass).error(message); + } + + public static String getObjectAttr(Object srcObj, String[] attrNames) { + StringBuilder attrText = new StringBuilder(); + if(srcObj!=null && attrNames!=null) { + try { + JSONObject jsonObject = (JSONObject)JSONObject.toJSON(srcObj); + + for(String attr:attrNames) { + attrText.append(attr).append("="); + if(jsonObject.containsKey(attr)) { + attrText.append(jsonObject.getString(attr)); + } + attrText.append(";"); + } + + }catch(Exception ignored) { + + } + } + return attrText.toString(); + } + + public static String getFormatLog(String operationTag, String dataTag, boolean isSuccess, String resultTag,String message) { + String logMessage = ""; + String statusMsg = (resultTag==null?"":resultTag); + String errorMsg = (message==null?"":message); + logMessage = operationTag+(StringUtils.isBlank(dataTag)?"":" ["+dataTag+"]"); + if(isSuccess) { + logMessage += (" successed" + (StringUtils.isBlank(statusMsg)?"":" with ["+statusMsg+"]")); + }else { + logMessage += (" failed with error ["+errorMsg+"]"); + } + + return logMessage; + } + + public static String getAjaxFormatLog(BaseApiResponse result, String operation, String[] reqAttr, String[] resultAttr) { + String logMessage = ""; + if(result!=null) { + String reqTxt = getObjectAttr(result.getRequestData(),reqAttr); + String resultTxt = getObjectAttr(result.getData(),resultAttr); + logMessage = getFormatLog(operation,reqTxt,result.isSuccess(),resultTxt,result.getMessage()); + } + return logMessage; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/utils/MailConfig.java b/src/main/java/com/mgm/mcrm/common/utils/MailConfig.java new file mode 100644 index 0000000..380b272 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/utils/MailConfig.java @@ -0,0 +1,88 @@ +package com.mgm.mcrm.common.utils; + +import java.io.File; +import java.util.List; +import java.util.Map; + +import jakarta.annotation.Resource; +import jakarta.mail.MessagingException; +import jakarta.mail.internet.MimeMessage; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.FileSystemResource; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSenderImpl; +import org.springframework.mail.javamail.MimeMessageHelper; + +@Configuration +public class MailConfig { + +// @Resource +// private JavaMailSenderImpl mailSender; +// +// @Value("${spring.mail.username}") +// private String username; +// +// /** +// * 发送纯文本形式的email +// * +// * @param toEmail 收件人邮箱 +// * @param title 邮件标题 +// * @param content 邮件内容 +// */ +// public void sendTextMail(String toEmail, String title, String content) { +// SimpleMailMessage msg = new SimpleMailMessage(); +// msg.setFrom(username); +// msg.setTo(toEmail); +// msg.setSubject(title); +// msg.setText(content); +// mailSender.send(msg); +// } +// +// /** +// * 发送带有html的内容 +// * +// * @param toEmail 收件人邮箱 +// * @param title 邮件标题 +// * @param htmlContent 邮件内容 +// */ +// public void sendHtmlMail(String toEmail, String title, String htmlContent) throws MessagingException { +// MimeMessage msg = mailSender.createMimeMessage(); +// MimeMessageHelper helper = new MimeMessageHelper(msg, false, "utf-8"); +// helper.setFrom(username); +// helper.setTo(toEmail); +// helper.setSubject(title); +// helper.setText(htmlContent, true); +// mailSender.send(msg); +// } +// +// /** +// * 添加附件的email发送 +// * +// * @param toEmail 收件人地址 +// * @param title 邮件标题 +// * @param content 文本内容 +// * @param aboutFiles 附件信息 每个子项都是一个文件相关信息的map Map: 1.filePath +// * 2.fileName +// * @throws Exception 异常 +// */ +// public void sendAttachmentMail(String toEmail, String title, String content, List> aboutFiles) throws Exception { +// MimeMessage msg = mailSender.createMimeMessage(); +// MimeMessageHelper helper = new MimeMessageHelper(msg, true, "utf-8"); +// helper.setFrom(username); +// helper.setTo(toEmail); +// helper.setSubject(title); +// helper.setText(content); +// FileSystemResource resource = null; +// for (Map file : aboutFiles) { +// resource = new FileSystemResource(file.get("filePath")); +// if (resource.exists()) {// 是否存在资源 +// File attachmentFile = resource.getFile(); +// helper.addAttachment(file.get("fileName"), attachmentFile); +// } +// } +// mailSender.send(msg); +// } + +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/common/utils/MessageReceiverListenerImpl.java b/src/main/java/com/mgm/mcrm/common/utils/MessageReceiverListenerImpl.java new file mode 100644 index 0000000..2091dfe --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/utils/MessageReceiverListenerImpl.java @@ -0,0 +1,54 @@ +package com.mgm.mcrm.common.utils; + +import org.jsmpp.bean.AlertNotification; +import org.jsmpp.bean.DataSm; +import org.jsmpp.bean.DeliverSm; +import org.jsmpp.bean.DeliveryReceipt; +import org.jsmpp.bean.MessageType; +import org.jsmpp.extra.ProcessRequestException; +import org.jsmpp.session.DataSmResult; +import org.jsmpp.session.MessageReceiverListener; +import org.jsmpp.session.Session; +import org.jsmpp.util.InvalidDeliveryReceiptException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MessageReceiverListenerImpl implements MessageReceiverListener { + + private static final Logger LOGGER = LoggerFactory.getLogger(MessageReceiverListenerImpl.class); + private static final String DATASM_NOT_IMPLEMENTED = "data_sm not implemented"; + + @Override + public DataSmResult onAcceptDataSm(DataSm dataSm, Session source) throws ProcessRequestException { + // TODO Auto-generated method stub + // throws ProcessRequestException { + LOGGER.info("DataSm not implemented"); + return null ; + /// throw new ProcessRequestException(DATASM_NOT_IMPLEMENTED, SMPPConstant.STAT_ESME_RINVCMDID); + } + + @Override + public void onAcceptDeliverSm(DeliverSm deliverSm) throws ProcessRequestException { + // TODO Auto-generated method stub + if (MessageType.SMSC_DEL_RECEIPT.containedIn(deliverSm.getEsmClass())) { + + try { + DeliveryReceipt delReceipt = deliverSm.getShortMessageAsDeliveryReceipt(); + + long id = Long.parseLong(delReceipt.getId()) & 0xffffffff; + String messageId = Long.toString(id, 16).toUpperCase(); + + LOGGER.info("Receiving delivery receipt for message '{}' from {} to {}: {}", + messageId, deliverSm.getSourceAddr(), deliverSm.getDestAddress(), delReceipt); + } catch (InvalidDeliveryReceiptException e) { + LOGGER.error("Failed getting delivery receipt", e); + } + } + } + + @Override + public void onAcceptAlertNotification(AlertNotification alertNotification) { + // TODO Auto-generated method stub + LOGGER.info("AlertNotification not implemented"); + } +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/common/utils/NetworkUtil.java b/src/main/java/com/mgm/mcrm/common/utils/NetworkUtil.java new file mode 100644 index 0000000..240a994 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/utils/NetworkUtil.java @@ -0,0 +1,378 @@ +package com.mgm.mcrm.common.utils; + +import java.net.*; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import jakarta.servlet.http.HttpServletRequest; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.text.StringEscapeUtils; +import org.springframework.web.util.UriUtils; +import com.mgm.mcrm.common.constants.SysCommon; + + +public class NetworkUtil { + private static List interalIpPatterns = new ArrayList(); + private static final Pattern IPV4_PATTERN = + Pattern.compile("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"); + private static final List INTERNAL_IP_PREFIXES = Arrays.asList( + "10.", "192.168.", "172.16.", "172.17.", "172.18.", "172.19.", + "172.20.", "172.21.", "172.22.", "172.23.", "172.24.", "172.25.", + "172.26.", "172.27.", "172.28.", "172.29.", "172.30.", "172.31." + ); + + public static void setInternalIpPattern(String patternConfig) { + interalIpPatterns.clear(); + String[] patternItems = patternConfig.split(";"); + for(String pItem:patternItems) { + String pVal = pItem.trim(); + if(StringUtils.isNotBlank(patternConfig)) { + interalIpPatterns.add(pVal); + } + } + } + + public static boolean isMatchInternal(String ipContent) { + boolean internalFlag = false; + if(StringUtils.isNotBlank(ipContent) && interalIpPatterns.size()>0) { + String ipPart = "\\b(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\b"; + for(String ipItem:interalIpPatterns) { + if(ipItem.contains("*")) { + String itemPattern = ipItem.replace(".", "\\."); + itemPattern = itemPattern.replace("*", ipPart); + Pattern pt = Pattern.compile(itemPattern); + Matcher mt = pt.matcher(ipContent); + if(mt.find()) { + internalFlag=true; + break; + } + }else { + if(ipContent.contains(ipItem)) { + internalFlag=true; + break; + } + } + } + } + return internalFlag; + } + + /** + * Gets the client ip addr. + * + * @param request the request + * @return the client ip addr + */ + public static String getClientIpAddr(HttpServletRequest request) { + String ip = getIpFromHeaders(request); + if(ip==null){ + ip = request.getRemoteAddr(); + } + return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip; + } + + private static String getIpFromHeaders(HttpServletRequest request) { + String[] headerNames = { + "X-Real-IP", + "X-Forwarded-For", + "Proxy-Client-IP", + "WL-Proxy-Client-IP", + "HTTP_CLIENT_IP", + "HTTP_X_FORWARDED_FOR" + }; + boolean isContainForwardHeader=false; + for (String headerName : headerNames) { + String headerValue = request.getHeader(headerName); + if (headerValue != null && !headerValue.isEmpty()) { + isContainForwardHeader=true; + LogUtil.info(NetworkUtil.class,"Check header["+headerName+"] of value["+headerValue+"]"); + String ip = extractValidIp(headerValue); + if (ip != null) { + return ip; + }else{ + LogUtil.info(NetworkUtil.class,"Header is not empty but not valid IP"); + } + } + } + return (isContainForwardHeader?"INVALID_IP":null); + } + + private static String extractValidIp(String headerValue) { + if (headerValue.contains(",")) { + String[] ips = headerValue.split(","); + for(int i=ips.length-1;i>=0;i--){ + String ip = ips[i].trim(); + if (isValidPublicIp(ip)) { + return ip; + } + } + return isValidIp(ips[ips.length - 1].trim())?ips[ips.length - 1].trim():null; + } else { + String ip = headerValue.trim(); + return isValidIp(ip) ? ip : null; + } + } + + private static boolean isValidPublicIp(String ip) { + return isValidIp(ip) && !isInternalIp(ip); + } + + private static boolean isValidIp(String ip) { + return ip != null && !ip.isEmpty() && + !"unknown".equalsIgnoreCase(ip) && + IPV4_PATTERN.matcher(ip).matches(); + } + + private static boolean isInternalIp(String ip) { + if (ip == null) return false; + if (ip.equals("127.0.0.1") || ip.equals("0:0:0:0:0:0:0:1")) { + return true; + } + for (String prefix : INTERNAL_IP_PREFIXES) { + if (ip.startsWith(prefix)) { + return true; + } + } + return false; + } + + /** + * Gets the real ips. + * + * @return the real ips + */ + public static List getRealIps() { + List ips = new ArrayList(); + String localip = null;// 本地IP,如果没有配置外网IP则返回它 + String netip = null;// 外网IP + Enumeration netInterfaces; + try { + netInterfaces = NetworkInterface.getNetworkInterfaces(); + } catch (SocketException e) { + return null; + } + + InetAddress ip = null; + boolean finded = false;// 是否找到外网IP + while (netInterfaces.hasMoreElements() && !finded) { + NetworkInterface ni = netInterfaces.nextElement(); + Enumeration address = ni.getInetAddresses(); + while (address.hasMoreElements()) { + ip = address.nextElement(); + if (!ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == -1) {// 外网IP + netip = ip.getHostAddress(); + ips.add(netip); + finded = true; + break; + } else if (ip.isSiteLocalAddress() && !ip.isLoopbackAddress() + && ip.getHostAddress().indexOf(":") == -1) {// 内网IP + localip = ip.getHostAddress(); + ips.add(localip); + } + } + } + return ips; + } + + /** + * Gets the real ip. + * + * @return the real ip + */ + public static String getRealIp() { + return getRealIps().iterator().next(); + } + + /** + * 获取访问者内网IP + * + * @return the server ip + */ + public static String getInternalIp() { + // 本地IP,如果没有配置外网IP则返回它 + String localip = null; + // 外网IP + String netip = null; + try { + Enumeration netInterfaces = NetworkInterface.getNetworkInterfaces(); + InetAddress ip = null; + // 是否找到外网IP + boolean finded = false; + while (netInterfaces.hasMoreElements() && !finded) { + NetworkInterface ni = (NetworkInterface) netInterfaces.nextElement(); + Enumeration address = ni.getInetAddresses(); + while (address.hasMoreElements()) { + ip = (InetAddress) address.nextElement(); + if (!ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == -1) { + // 外网IP + netip = ip.getHostAddress(); + finded = true; + break; + } else if (ip.isSiteLocalAddress() && !ip.isLoopbackAddress() + && ip.getHostAddress().indexOf(":") == -1) { + // 内网IP + localip = ip.getHostAddress(); + } + } + } + } catch (SocketException e) { + e.printStackTrace(); + } + + if (netip != null && !"".equals(netip)) { + return netip; + } else { + return localip; + } + } + + /** + * 判断ip是否在网段cidr内,cidr格式192.168.0.1/255 + * + * @return the server ip + */ + public static boolean ipInRange(String ip, String cidr) { + try { + String[] tmp = cidr.split("/"); + + if (tmp.length > 1) { + + String[] ips = ip.split("\\."); + int ipAddr = (Integer.parseInt(ips[0]) << 24) | (Integer.parseInt(ips[1]) << 16) + | (Integer.parseInt(ips[2]) << 8) | Integer.parseInt(ips[3]); + int type = Integer.parseInt(cidr.replaceAll(".*/", "")); + int mask = 0xFFFFFFFF << (32 - type); + String cidrIp = cidr.replaceAll("/.*", ""); + String[] cidrIps = cidrIp.split("\\."); + int cidrIpAddr = (Integer.parseInt(cidrIps[0]) << 24) | (Integer.parseInt(cidrIps[1]) << 16) + | (Integer.parseInt(cidrIps[2]) << 8) | Integer.parseInt(cidrIps[3]); + return (ipAddr & mask) == (cidrIpAddr & mask); + } else if (tmp.length == 1 && ip.equals(cidr)) { + return true; + } else { + return false; + } + } catch (Exception ex) { + ex.printStackTrace(); + return false; + } + } + + public static String getServerName() { + String serverName=""; + try { + InetAddress localhost = InetAddress.getLocalHost(); + serverName = localhost.getHostName(); + } catch (Exception e) { + e.printStackTrace(); + } + return serverName; + } + + /** + * 判断ip是否在网段cidr内,cidr格式192.168.0.1/255 + * + * @return the server ip + */ + public static boolean isMacauIp(String ip,String macauIps) { + try { + String[] cidrArr = StringUtils.split(macauIps,";"); + if(cidrArr.length>0) { + for(String cidr : cidrArr) { + String[] tmp = cidr.split("/"); + if (tmp.length > 1) { + String[] ips = ip.split("\\."); + try { + Integer.parseInt(ips[0]); + Integer.parseInt(ips[1]); + Integer.parseInt(ips[2]); + Integer.parseInt(ips[3]); + } catch (Exception e) { + continue; + } + int ipAddr = (Integer.parseInt(ips[0]) << 24) | (Integer.parseInt(ips[1]) << 16) + | (Integer.parseInt(ips[2]) << 8) | Integer.parseInt(ips[3]); + int type = Integer.parseInt(cidr.replaceAll(".*/", "")); + int mask = 0xFFFFFFFF << (32 - type); + String cidrIp = cidr.replaceAll("/.*", ""); + String[] cidrIps = cidrIp.split("\\."); + int cidrIpAddr = (Integer.parseInt(cidrIps[0]) << 24) | (Integer.parseInt(cidrIps[1]) << 16) + | (Integer.parseInt(cidrIps[2]) << 8) | Integer.parseInt(cidrIps[3]); + if((ipAddr & mask) == (cidrIpAddr & mask)) return true; + } else if (tmp.length == 1 && ip.equals(cidr)) { + return true; + } + } + }else { + return false; + } + + } catch (Exception ex) { + ex.printStackTrace(); + return false; + } + return false; + } + + public static boolean isRequestFromTrustedSource(HttpServletRequest request) { + if(StringUtils.isNotBlank(request.getHeader("x-forwarded-for")) + ||StringUtils.isNotBlank(request.getHeader("Proxy-Client-IP")) + ||StringUtils.isNotBlank(request.getHeader("WL-Proxy-Client-IP")) + ||StringUtils.isNotBlank(request.getHeader("HTTP_CLIENT_IP")) + ||StringUtils.isNotBlank(request.getHeader("HTTP_X_FORWARDED_FOR"))){ + + String remoteAddr = request.getRemoteAddr(); + if(SysCommon.isAllowIPSource(remoteAddr)) { + LogUtil.warn(NetworkUtil.class, "IP remoteAddr="+remoteAddr); + return true; + }else { + LogUtil.warn(NetworkUtil.class, "IP of ["+remoteAddr+"] is not allowed proxy IP"); + return false; + } + }else{ + return true; + } + } + + public static boolean isValidURL(String requestUrl){ + try { + URI uri = new URI(requestUrl); + String scheme = uri.getScheme(); + String host = uri.getHost(); + if(!"https".equals(scheme) && !"http".equals(scheme)) { + return false; + } + if(host.matches("\\d+\\.\\d+\\.\\d+\\.\\d+")) { + return false; + } + return true; + } catch (Exception e) { + return false; + } + } + + public static String encodeParaWithSpring(String value) { + if(value==null) + value=""; + value= value.replace("\r", "").replace("\n", ""); + return UriUtils.encode(value, StandardCharsets.UTF_8); + } + + public static String sanitizeHeaderValue(String headerValue) { + return headerValue==null? null :(StringEscapeUtils.escapeJava(headerValue) + .replace("\\r", "") + .replace("\\n", "")); + } + + public static String encodePathWithSpring(String value) { + if(value==null) + value=""; + value= value.replace("\r", "").replace("\n", ""); + return UriUtils.encodePath(value, StandardCharsets.UTF_8); + } +} diff --git a/src/main/java/com/mgm/mcrm/common/utils/PDFUtil.java b/src/main/java/com/mgm/mcrm/common/utils/PDFUtil.java new file mode 100644 index 0000000..6ef5a3d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/utils/PDFUtil.java @@ -0,0 +1,102 @@ +package com.mgm.mcrm.common.utils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import org.apache.commons.io.IOUtils; + +import com.mgm.mcrm.common.constants.SysCommon; + +/** + * Converting html file to Pdf file With parallel Output and error stream for + * the process + * + * @author Ankur + * + */ +public class PDFUtil { + + public static void makeAPdfWithStreams(String command, String htmlUrl, String pdfFileName) + throws InterruptedException, IOException { + Process wkhtml; + + String runCommand = command + " " + htmlUrl + " " + pdfFileName; + wkhtml = Runtime.getRuntime().exec(runCommand); // Start process + + Thread errThread = new Thread(() -> { + try { + IOUtils.copy(wkhtml.getErrorStream(), System.err); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + Thread htmlReadThread = new Thread(() -> { + try { + IOUtils.copy(wkhtml.getErrorStream(), System.out); + wkhtml.getOutputStream().flush(); + wkhtml.getOutputStream().close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + + // Do NOT use Run... it should be clear why, you want them to all be going at + // the same time. + errThread.start(); + htmlReadThread.start(); + wkhtml.waitFor(); // Allow process to run + } + + public static boolean convertHtml2Pdf(String htmlFileName, String pdfFileName) { + boolean isGenerate = false; + // 创建pdf + String runPdfCommand = SysCommon.runtime_path + "/wkhtmltopdf/bin/wkhtmltopdf"; + try { + makeAPdfWithStreams(runPdfCommand, htmlFileName, pdfFileName); + isGenerate =true; + } catch (Exception e) { + LogUtil.error(PDFUtil.class, "Generate PDF failed:"+e.getMessage()); + isGenerate =false; + } + return isGenerate; + } + + public void HtmlToPdfInterceptor(InputStream is){ + Thread htmlReadThread = new Thread(() -> { + try { + InputStreamReader isr = new InputStreamReader(is, "utf-8"); + BufferedReader br = new BufferedReader(isr); + String line = null; + while ((line = br.readLine()) != null) { + System.out.print(line.toString()); // 输出内容 + } + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + + public static StringBuilder getFormal() { + StringBuilder cmd = new StringBuilder(); + cmd.append(" "); + cmd.append(" --header-line");// 页眉下面的线 +// cmd.append(" --footer-line");//页脚上面的线 + cmd.append(" --footer-center [page]/[topage]"); // 在页脚中心放置页码 +// cmd.append(" --header-right 这里是我们系统的页眉"); //页眉中间放置文字 + cmd.append(" --header-html http://localhost:8090/myheader.html"); // 页眉中间放置图片 + cmd.append(" --header-spacing 5 ");// (设置页眉和内容的距离,默认0 ) + cmd.append(" --margin-top 20mm "); // 设置页面上边距 (default 10mm) + cmd.append(" cover http://localhost:8090/firstPage.html "); + cmd.append(" --outline"); + cmd.append(" cover http://image.baidu.com"); + cmd.append("--disable-smart-shrinking "); + cmd.append("--load-media-error-handling "); + cmd.append("--load-error-handling "); + cmd.append("--footer-font-size 11 "); + return cmd; + } + + + +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/common/utils/SOAPUtil.java b/src/main/java/com/mgm/mcrm/common/utils/SOAPUtil.java new file mode 100644 index 0000000..631be70 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/utils/SOAPUtil.java @@ -0,0 +1,337 @@ +package com.mgm.mcrm.common.utils; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.StringReader; +import java.io.StringWriter; +import java.net.*; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Iterator; +import java.util.List; +import org.apache.commons.lang3.StringUtils; + +import jakarta.xml.soap.SOAPEnvelope; +import jakarta.xml.soap.SOAPException; +import jakarta.xml.soap.SOAPMessage; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.NodeList; +import com.mgm.mcrm.common.constants.SysCommon; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import jakarta.xml.soap.MessageFactory; +import jakarta.xml.soap.Node; +import jakarta.xml.soap.SOAPBody; +import jakarta.xml.soap.SOAPElement; +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.JAXBException; +import jakarta.xml.bind.Marshaller; +import jakarta.xml.bind.Unmarshaller; +import javax.xml.namespace.QName; + + +public class SOAPUtil { + + /* + * 远程访问SOAP协议接口 + * + * @param url: 服务接口地址"http://192.168.0.120:8222/HelloWorld?wsdl" + * @param isClass:接口类名 + * @param isMethod: 接口方法名 + * @param sendSoapString: soap协议xml格式访问接口 + * + * @return soap协议xml格式 + * + * @备注:有四种请求头格式1、SOAP 1.1; 2、SOAP 1.2 ; 3、HTTP GET; 4、HTTP POST + * 参考---》http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?op=getWeatherbyCityName + */ + + public static String getWebServiceSOAP(String url,String action,StringBuffer sendSoapString){ + String soap = sendSoapString.toString(); + if (soap == null) { + return null; + } + + try { + URL soapUrl = new URL(url); + boolean isHttps = url.startsWith("https"); + HttpURLConnection conn = (HttpURLConnection) soapUrl.openConnection(); + if(isHttps) { + HttpsURLConnection https = (HttpsURLConnection) conn; + trustAllHosts(https); + https.setHostnameVerifier(checkSoapServer); + } + conn.setUseCaches(false); + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setRequestProperty("Content-Length", + Integer.toString(soap.length())); + conn.setRequestProperty("Content-Type", "text/xml; charset=GBK"); + conn.setConnectTimeout(SysCommon.apiConfig.getTimeout_OWS()); + conn.setReadTimeout(SysCommon.apiConfig.getTimeout_OWS()); + // 调用的接口方法是 + conn.setRequestProperty("SOAPAction",action); + OutputStream os = conn.getOutputStream(); + OutputStreamWriter osw = new OutputStreamWriter(os, "GBK"); + osw.write(soap); + osw.flush(); + osw.close(); + // 获取webserivce返回的流 + InputStream is = conn.getInputStream(); + String sCurrentLine = ""; + StringBuilder sTotalString = new StringBuilder(); + if (is!=null) { + BufferedReader l_reader = new BufferedReader(new InputStreamReader(is)); + while ((sCurrentLine = l_reader.readLine()) != null) { + sTotalString.append(sCurrentLine); + } + is.close(); + return sTotalString.toString(); + }else { + is.close(); + return null; + } + }catch(Exception ex) { + ex.printStackTrace(); + } + return null; + } + + public static String getWebServiceSOAPUTF(String url,String action,StringBuffer sendSoapString){ + String soap = sendSoapString.toString(); + if (soap == null) { + return null; + } + + try { + URL soapUrl = new URL(url); + boolean isHttps = url.startsWith("https"); + HttpURLConnection conn = (HttpURLConnection) soapUrl.openConnection(); + if(isHttps) { + HttpsURLConnection https = (HttpsURLConnection) conn; + trustAllHosts(https); + https.setHostnameVerifier(checkSoapServer); + } + conn.setUseCaches(false); + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setRequestProperty("Content-Length", + Integer.toString(soap.length())); + conn.setRequestProperty("Content-Type", "text/xml; charset=utf-8"); + // 调用的接口方法是 + conn.setRequestProperty("SOAPAction",action); + OutputStream os = conn.getOutputStream(); + OutputStreamWriter osw = new OutputStreamWriter(os, "GBK"); + osw.write(soap); + osw.flush(); + osw.close(); + // 获取webserivce返回的流 + InputStream is = conn.getInputStream(); + String sCurrentLine = ""; + StringBuilder sTotalString = new StringBuilder(); + if (is!=null) { + BufferedReader l_reader = new BufferedReader(new InputStreamReader(is)); + while ((sCurrentLine = l_reader.readLine()) != null) { + sTotalString.append(sCurrentLine); + } + is.close(); + return sTotalString.toString(); + }else { + is.close(); + return null; + } + }catch(Exception ex) { + ex.printStackTrace(); + } + return null; + } + + public static SOAPMessage getSOAPMessageFromXMLString(String xmlString) { + + SOAPMessage soapMessage = null; + try { + InputStream is = new ByteArrayInputStream(xmlString.getBytes()); + soapMessage = MessageFactory.newInstance().createMessage(null, is); + //SOAPEnvelope soapEnvelope = soapMessage.getSOAPPart().getEnvelope(); + //soapEnvelope.addNamespaceDeclaration(namespacePrefix, namespaceURI); + //soapMessage.saveChanges(); + } catch (Exception e) { + e.printStackTrace(); + } + return soapMessage; + } + + private static final TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() { + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new java.security.cert.X509Certificate[] {}; + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String arg1) throws CertificateException { + if (chain == null || chain.length == 0) { + throw new IllegalArgumentException("No server certificates provided"); + } + for (X509Certificate cert : chain) { + cert.checkValidity(); + } + } + + @Override + public void checkClientTrusted(X509Certificate[] chain, String arg1) throws CertificateException { + if (chain == null || chain.length == 0) { + throw new CertificateException("No client certificates provided"); + } + for (X509Certificate cert : chain) { + cert.checkValidity(); // 检查证书是否在有效期内 + } + } + }}; + + private static final HostnameVerifier checkSoapServer = new HostnameVerifier() { + public boolean verify(String hostname, SSLSession session) { + boolean isServerAllow = SysCommon.isAllowSoapServer(hostname); + if(isServerAllow==false) { + LogUtil.warn(SOAPUtil.class, "SOAP Server of ["+hostname+"] is not allowed"); + } + return SysCommon.isAllowSoapServer(hostname); + } + }; + + + /** + * 信任所有 + * @param connection + * @return + */ + private static SSLSocketFactory trustAllHosts(HttpsURLConnection conn) { + SSLSocketFactory oldFactory = conn.getSSLSocketFactory(); + try { + SSLContext sc = SSLContext.getInstance("TLS"); + sc.init(null, trustAllCerts, new java.security.SecureRandom()); + SSLSocketFactory newFactory = sc.getSocketFactory(); + conn.setSSLSocketFactory(newFactory); + } catch (Exception e) { + e.printStackTrace(); + } + return oldFactory; + } + + public static String convertObjectToXml( T response){ + try { + JAXBContext ctx = JAXBContext.newInstance(response.getClass()); + Marshaller marshaller = ctx.createMarshaller(); + //marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true); + StringWriter stringWriter = new StringWriter(); + marshaller.marshal(response, stringWriter); + return stringWriter.toString(); + } catch (JAXBException e) { + e.printStackTrace(); + return null; + } + } + public static T convertXmlToObject(String xml, Class responseType){ + try { + JAXBContext ctx = JAXBContext.newInstance(new Class[]{responseType}); + Unmarshaller um = ctx.createUnmarshaller(); + return (T) um.unmarshal(new StringReader(xml)); + } catch (JAXBException e) { + e.printStackTrace(); + return null; + } + } + + public static SOAPMessage createSOAPMessageByObject(List nameSpaces, Object msgHeader, Object bean) throws Exception { + SOAPMessage soapMessage = null; + try { + soapMessage = MessageFactory.newInstance().createMessage(); + JAXBContext ctx = JAXBContext.newInstance(bean.getClass()); + Marshaller marshaller = ctx.createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true); + SOAPEnvelope envelop = soapMessage.getSOAPPart().getEnvelope(); + if(nameSpaces!=null && nameSpaces.size()>0) { + for(QName qNameItem:nameSpaces) { + envelop.addNamespaceDeclaration(qNameItem.getPrefix(),qNameItem.getNamespaceURI()); + } + } + if(msgHeader!=null) { + JAXBContext hdctx = JAXBContext.newInstance(msgHeader.getClass()); + Marshaller headerMarshaller = hdctx.createMarshaller(); + headerMarshaller.marshal(msgHeader, envelop.getHeader()); + } + SOAPBody body= soapMessage.getSOAPPart().getEnvelope().getBody(); + marshaller.marshal(bean, body); + removeBodyNullAttributes(body); + }catch(Exception err) { + err.printStackTrace(); + } + return soapMessage; + } + + public static T getObjectFromSOAPMessage(SOAPMessage soapMessage, Class beanClass) throws Exception { + T result =null; + try { + JAXBContext ctx = JAXBContext.newInstance(beanClass); + Unmarshaller um = ctx.createUnmarshaller(); + result = (T) um.unmarshal(soapMessage.getSOAPBody(),beanClass).getValue(); + } catch (JAXBException e) { + e.printStackTrace(); + //return null; + } + return result; + } + + public static void removeBodyNullAttributes(SOAPBody body) throws SOAPException, IOException { // 遍历所有的元素 + Iterator nodeIterator = body.getChildElements(); + while (nodeIterator.hasNext()) { + removeNullAttributes(nodeIterator.next()); + } + } + + private static void removeNullAttributes(Node node) throws SOAPException { + if (node instanceof SOAPElement) { + SOAPElement element = (SOAPElement) node; + if(StringUtils.isBlank(element.getNamespaceURI()) + && StringUtils.isNotBlank(node.getParentElement().getNamespaceURI())) { + QName newQName = new QName( + node.getParentElement().getNamespaceURI(), + element.getLocalName(), + node.getParentElement().getPrefix() + ); + element.setElementQName(newQName); + } + NamedNodeMap attributes = element.getAttributes(); + if(attributes!=null) { + for (int i = 0; i < attributes.getLength(); i++) { + Node attribute = (Node) attributes.item(i); + if (element.getAttribute(attribute.getNodeName()) == null) { + element.removeAttribute(attribute.getNodeName()); + i--; + } + } + } + } + // 递归遍历子节点 + NodeList children = node.getChildNodes(); + if(children!=null) { + for (int i = 0; i < children.getLength(); i++) { + Node childNode = (Node) children.item(i); + removeNullAttributes(childNode); + } + } + } +} diff --git a/src/main/java/com/mgm/mcrm/common/utils/SendEmail.java b/src/main/java/com/mgm/mcrm/common/utils/SendEmail.java new file mode 100644 index 0000000..eda4cdf --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/utils/SendEmail.java @@ -0,0 +1,956 @@ +package com.mgm.mcrm.common.utils; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Properties; + +import com.mgm.mcrm.booking.models.BookingsView; +import jakarta.mail.Session; +import jakarta.mail.internet.MimeMessage; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.springframework.mail.javamail.JavaMailSenderImpl; +import org.springframework.mail.javamail.MimeMessageHelper; +import com.alibaba.fastjson.JSONObject; + +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.notification.models.CfgEmailTemplate; +import com.mgm.mcrm.notification.models.Email; +import com.mgm.mcrm.common.dtos.EumnApprovalStatus; + +public class SendEmail { + + + public static int mail_port=25; + public static String mail_smtp_host=""; + public static String mail_sender=""; + public static String mail_sender_password=""; + public static String mail_to=""; + public static String mail_Bcc=""; + + private static String emailTemp = "
Submission Date & Time:{{ttime}}
"+ + "
Submitted User:{{tuser}}
"+ + "

" + + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " {{tbody}}"+ + " \r\n" + + "
\r\n" + + " Conf#\r\n" + + " \r\n" + + " Booking Status\r\n" + + " \r\n" + + " Member ID\r\n" + + " \r\n" + + " Member Name\r\n" + + " \r\n" + + " Tier\r\n" + + " \r\n" + + " Property\r\n" + + " \r\n" + + " Room Type\r\n" + + " \r\n" + + " Sharer\r\n" + + " \r\n" + + " Original C/I\r\n" + + " \r\n" + + " Original C/O\r\n" + + " \r\n" + + " Extending C/O\r\n" + + "
"; + + private static String emailApprovalTemp = "
Submission Date & Time:{{ttime}}
"+ + "
Submitted and Approver:{{tuser}}
"+ + "

" + + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" +" \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " {{tbody}}"+ + " \r\n" + + "
\r\n" + + " Booking Status\r\n" + + " \r\n" + + " Conf#\r\n" + + " \r\n" + + " Member ID\r\n" + + " \r\n" + + " Member Name\r\n" + + " \r\n" + + " Tier\r\n" + + " \r\n" + + " Property\r\n" + + " \r\n" + + " Room Type\r\n" + + " \r\n" + + " Sharer\r\n" + + " \r\n" + + " Type\r\n" + + " \r\n" + + " Requested C/I\r\n" + + " \r\n" + + " Requested C/O\r\n" + + " \r\n" + + " Approved Property\r\n" + + " \r\n" + + " Approved Room Type\r\n" + + " \r\n" + + " Approved C/I\r\n" + + " \r\n" + + " Approved C/O\r\n" + + " \r\n" + + " Booker Team\r\n" + + " \r\n" + + " Booker ID\r\n" + + " \r\n" + + " Booker Name\r\n" + + " \r\n" + + " Approval Remark\r\n" + + " \r\n" + + " Remark\r\n" + + "
"; + + private static String emailNewApprovalTemp = "
Submission Date & Time:{{ttime}}
"+ + "
Submitted and Approver:{{tuser}}
"+ + "

" + + "{{content}}"+ + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " {{tbody}}"+ + " \r\n" + + "
\r\n" + + " Booking Status\r\n" + + " \r\n" + + " Member ID\r\n" + + " \r\n" + + " Member Name\r\n" + + " \r\n" + + " Tier\r\n" + + " \r\n" + + " Property\r\n" + + " \r\n" + + " Room Type\r\n" + + " \r\n" + + " Sharer\r\n" + + " \r\n" + + " Type\r\n" + + " \r\n" + + " Requested C/I\r\n" + + " \r\n" + + " Requested C/O\r\n" + + " \r\n" + + " Booker Team\r\n" + + " \r\n" + + " Booker ID\r\n" + + " \r\n" + + " Booker Name\r\n" + + " \r\n" + + " Approval Remark\r\n" + + " \r\n" + + " Remark\r\n" + + "
"; + + private static String cancelEmailTemp = "
Submission Date & Time:{{ttime}}
"+ + "
Submitted User:{{tuser}}
"+ + "

" + + "{{content}}"+ + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " {{tbody}}"+ + " \r\n" + + "
\r\n" + + " Conf#\r\n" + + " \r\n" + + " Booking Status\r\n" + + " \r\n" + + " Member ID\r\n" + + " \r\n" + + " Member Name\r\n" + + " \r\n" + + " Tier\r\n" + + " \r\n" + + " Property\r\n" + + " \r\n" + + " Room Type\r\n" + + " \r\n" + + " Sharer\r\n" + + " \r\n" + + " Type\r\n" + + " \r\n" + + " Original C/I\r\n" + + " \r\n" + + " Original C/O\r\n" + + " \r\n" + + " Change C/I\r\n" + + " \r\n" + + " Change C/O\r\n" + + "
"; + + + public static Email sendExtendEmail(Bookings book, BookingsView originBook, Email emailObj, String userId, String userName, String emailTo) { + String content1 = emailTemp; + try { + JavaMailSenderImpl sender = new JavaMailSenderImpl(); + if(StringUtils.isEmpty(mail_smtp_host)) { + mail_smtp_host = SysCommon.apiConfig.getHost_SMTP(); + } + mail_port = Integer.valueOf(SysCommon.apiConfig.getPort_SMTP()); + if(StringUtils.isEmpty(mail_sender)) { + mail_sender = SysCommon.apiConfig.getUsername_SMTP(); + } + if(StringUtils.isEmpty(mail_sender_password)) { + mail_sender_password = SysCommon.apiConfig.getPassword_SMTP(); + } + if(!StringUtils.isEmpty(emailTo)) { + mail_to = emailTo; + }else { + mail_to = SysCommon.apiConfig.getSend_to_SMTP(); + } + + sender.setHost(mail_smtp_host); + sender.setPort(mail_port); // 默认就是25 + sender.setUsername(mail_sender); + sender.setPassword(mail_sender_password);// + sender.setDefaultEncoding("UTF-8"); + + // 配置文件对象 + Properties props = new Properties(); + props.put("mail.smtp.auth", "false"); // 是否进行验证 + Session session = Session.getInstance(props); + sender.setSession(session); // 为发送器指定会话 + + MimeMessage mail = sender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(mail, true); + + String subTitle = ""; + helper.setSubject("[Urgent] Extension Request from Mobile CRM APP"+subTitle); // 标题 + helper.setFrom(mail_sender); // 来自 + + SimpleDateFormat sf = new SimpleDateFormat("dd-MMM-yyyy HH:mm"); + SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy"); + String RequestDate = sf.format(new Date()); + + String content2 = ""; + String tTime = RequestDate; + userId = !StringUtils.isEmpty(userId)?userId:""; + userName = !StringUtils.isEmpty(userName)?userName:""; + String tUser = userId+" "+userName; + String operaStatus = Strings.CS.replace(book.getLastOperaStatus(), "_", " "); + + content2 += ""+ + "" + +book.getConfirmationNo()+ + " "+ + "" + +operaStatus+ + " " + + "" + +book.getPlayerId()+ + " " + + "" + +book.getMemberLastName()+ + " " + + "" + +(originBook.getMemberTier()!=null?originBook.getMemberTier():"")+ + " " + + "" + +(originBook.getPropertyName()!=null?originBook.getPropertyName():"")+ + " " + + "" + +(originBook.getRoom()!=null?originBook.getRoom():"")+ + " "+ + "" + +(originBook.getSharerName()!=null?originBook.getSharerName():"")+ + " "+ + "" + +format.format(originBook.getCheckinDate())+ + " " + + "" + +format.format(originBook.getCheckoutDate())+ + " " + + "" + +format.format(book.getCheckoutDate())+ + " " + + " "; + + content1 = content1.replace("{{tbody}}", content2); + content1 = content1.replace("{{ttime}}", tTime); + content1 = content1.replace("{{tuser}}", tUser); + helper.setText(content1,true); // 邮件内容,第二个参数指定发送的是HTML格式 + JSONObject emailJson = new JSONObject(); + emailJson.put("conf", book.getConfirmationNo()); + emailJson.put("memberId", book.getPlayerId()); + emailJson.put("memberName", book.getMemberLastName()); + emailJson.put("tier", originBook.getMemberTier()); + emailJson.put("property", originBook.getPropertyName()); + emailJson.put("roomType", originBook.getRoom()); + emailJson.put("checkin", format.format(originBook.getCheckinDate())); + emailJson.put("checkout", format.format(originBook.getCheckoutDate())); + emailJson.put("extCheckout", format.format(book.getCheckoutDate())); + + emailObj.setSendObject(emailJson.toJSONString()); + emailObj.setContent(content1); + emailObj.setSendTo(mail_to); + String[] mailToArr = StringUtils.split(mail_to,";"); + if(mailToArr.length>1) { + for (String str : mailToArr) { + helper.setTo(str); + try { + sender.send(mail); // 发送 + emailObj.setStatus(1); + } catch (Exception e) { + emailObj.setMessage("Send Email to "+str+" Failed:"+e.getMessage()); + emailObj.setStatus(0); + } + + } + }else { + helper.setTo(mail_to); + try { + sender.send(mail); // 发送 + emailObj.setStatus(1); + LogUtil.info(SendEmail.class, "---mgmEmail.sendExtendEmail--OK!"); + } catch (Exception e) { + emailObj.setMessage("Send Email to "+mail_to+" Failed:"+e.getMessage()); + emailObj.setStatus(0); + LogUtil.error(SendEmail.class, "---mgmEmail.sendExtendEmail--Failed!"+e.getMessage()); + } + } + + } catch (Exception e) { + LogUtil.error(SendEmail.class,"---mgmEmail.sendExtenEmail--Exception-->>"+e.getMessage()); + emailObj.setMessage(e.getMessage()); + emailObj.setStatus(0); + } + + return emailObj; + } + + public static Email sendApprovalNewEmail(Bookings book,BookingsView bookView,Email emailObj,String userId,String userName,boolean isOverBook,boolean isConnectRoom,String emailTo) { + String content1 = emailNewApprovalTemp; + try { + JavaMailSenderImpl sender = new JavaMailSenderImpl(); + if(StringUtils.isEmpty(mail_smtp_host)) { + mail_smtp_host = SysCommon.apiConfig.getHost_SMTP(); + } + mail_port = Integer.valueOf(SysCommon.apiConfig.getPort_SMTP()); + if(StringUtils.isEmpty(mail_sender)) { + mail_sender = SysCommon.apiConfig.getUsername_SMTP(); + } + if(StringUtils.isEmpty(mail_sender_password)) { + mail_sender_password = SysCommon.apiConfig.getPassword_SMTP(); + } + if(!StringUtils.isEmpty(emailTo)) { + mail_to = emailTo; + }else { + mail_to = SysCommon.apiConfig.getSend_to_SMTP(); + } + sender.setHost(mail_smtp_host); + sender.setPort(mail_port); // 默认就是25 + sender.setUsername(mail_sender); + sender.setPassword(mail_sender_password);// + sender.setDefaultEncoding("UTF-8"); + + // 配置文件对象 + Properties props = new Properties(); + props.put("mail.smtp.auth", "false"); // 是否进行验证 + Session session = Session.getInstance(props); + sender.setSession(session); // 为发送器指定会话 + + MimeMessage mail = sender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(mail, true); + + String mainTitle; + if(isConnectRoom) { + mainTitle = "[R2/Y2]"; + }else if(isOverBook) { + mainTitle = "[Overbook]"; + }else { + mainTitle = "[Urgent]"; + } + helper.setSubject(mainTitle+"Waitlist Approval from Mobile CRM APP"); // 标题 + helper.setFrom(mail_sender); // 来自 + + SimpleDateFormat sf = new SimpleDateFormat("dd-MMM-yyyy HH:mm"); + SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy"); + String RequestDate = sf.format(new Date()); + + String content2 = ""; + String tTime = RequestDate; + userId = !StringUtils.isEmpty(userId)?userId:""; + userName = !StringUtils.isEmpty(userName)?userName:""; + String tUser = userId+" "+userName; + String approvalStatus = EumnApprovalStatus.getApprovalStatusByDBValue(book.getApproveStatus()); + + + content2 += ""+ + "" + +approvalStatus+ + " "+ + "" + +bookView.getPlayerId()+ + " " + + "" + +bookView.getMemberLastName()+ + " " + + "" + +(bookView.getMemberTier()!=null?bookView.getMemberTier():"")+ + " " + + "" + +(bookView.getPropertyName()!=null?bookView.getPropertyName():"")+ + " " + + "" + +(bookView.getRoom()!=null?bookView.getRoom():"")+ + " "+ + "" + +(bookView.getSharerName()!=null?bookView.getSharerName():"")+ + " " + + "" + +"New"+ + " "+ + "" + +format.format(bookView.getCheckinDate())+ + " " + + "" + +format.format(bookView.getCheckoutDate())+ + " " + + "" + +(bookView.getBookerTeam()!=null?bookView.getBookerTeam():"")+ + " " + + "" + +bookView.getCreatedBy()+ + " " + + "" + +bookView.getCreatedByName()+ + " " + + "" + +(bookView.getApprovalRemark()!=null?bookView.getApprovalRemark():"")+ + " " + + "" + +(bookView.getRemark()!=null?bookView.getRemark():"")+ + " " + + " "; + + String mailContent = isConnectRoom?"Please create TT/YY booking for below approved booking

":""; + content1 = content1.replace("{{tbody}}", content2); + content1 = content1.replace("{{ttime}}", tTime); + content1 = content1.replace("{{tuser}}", tUser); + content1 = content1.replace("{{content}}", mailContent); + helper.setText(content1,true); // 邮件内容,第二个参数指定发送的是HTML格式 + JSONObject emailJson = new JSONObject(); + emailJson.put("approvalStatus", approvalStatus); + emailJson.put("memberId", bookView.getPlayerId()); + emailJson.put("memberName", bookView.getMemberLastName()); + emailJson.put("tier", bookView.getMemberTier()); + emailJson.put("property", bookView.getPropertyName()); + emailJson.put("roomType", bookView.getRoom()); + emailJson.put("type", "New"); + emailJson.put("checkin", format.format(bookView.getCheckinDate())); + emailJson.put("checkout", format.format(bookView.getCheckoutDate())); + emailJson.put("bookerTeam", bookView.getBookerTeam()); + emailJson.put("bookerId", bookView.getCreatedBy()); + emailJson.put("bookerName", bookView.getCreatedByName()); + emailJson.put("approvalRemark", bookView.getApprovalRemark()); + emailJson.put("remark", bookView.getRemark()); + + emailObj.setSendObject(emailJson.toJSONString()); + emailObj.setContent(content1); + emailObj.setSendTo(mail_to); + String[] mailToArr = StringUtils.split(mail_to,";"); + if(mailToArr.length>1) { + for (String str : mailToArr) { + helper.setTo(str); + try { + sender.send(mail); // 发送 + emailObj.setStatus(1); + } catch (Exception e) { + emailObj.setMessage("Send Email to "+str+" Failed:"+e.getMessage()); + emailObj.setStatus(0); + } + + } + }else { + helper.setTo(mail_to); + try { + sender.send(mail); // 发送 + emailObj.setStatus(1); + LogUtil.info(SendEmail.class, "---mgmEmail.sendApprovalNewEmail--OK!"); + } catch (Exception e) { + emailObj.setMessage("Send Email to "+mail_to+" Failed:"+e.getMessage()); + emailObj.setStatus(0); + LogUtil.error(SendEmail.class, "---mgmEmail.sendApprovalNewEmail--Failed!"+e.getMessage()); + } + } + + } catch (Exception e) { + LogUtil.error(SendEmail.class,"---mgmEmail.sendApprovalNewEmail--Exception-->>"+e.getMessage()); + emailObj.setMessage(e.getMessage()); + emailObj.setStatus(0); + } + + return emailObj; + } + + public static Email sendApprovalExtendEmail(Bookings book,BookingsView originBook,Email emailObj,String userId,String userName,BookingsView viewBook,boolean isOverBook,String emailTo) { + String content1 = emailApprovalTemp; + try { + JavaMailSenderImpl sender = new JavaMailSenderImpl(); + if(StringUtils.isEmpty(mail_smtp_host)) { + mail_smtp_host = SysCommon.apiConfig.getHost_SMTP(); + } + mail_port = Integer.valueOf(SysCommon.apiConfig.getPort_SMTP()); + if(StringUtils.isEmpty(mail_sender)) { + mail_sender = SysCommon.apiConfig.getUsername_SMTP(); + } + if(StringUtils.isEmpty(mail_sender_password)) { + mail_sender_password = SysCommon.apiConfig.getPassword_SMTP(); + } + if(!StringUtils.isEmpty(emailTo)) { + mail_to = emailTo; + }else { + mail_to = SysCommon.apiConfig.getSend_to_SMTP(); + } + sender.setHost(mail_smtp_host); + sender.setPort(mail_port); // 默认就是25 + sender.setUsername(mail_sender); + sender.setPassword(mail_sender_password);// + sender.setDefaultEncoding("UTF-8"); + + // 配置文件对象 + Properties props = new Properties(); + props.put("mail.smtp.auth", "false"); // 是否进行验证 + Session session = Session.getInstance(props); + sender.setSession(session); // 为发送器指定会话 + + MimeMessage mail = sender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(mail, true); + + String subTitle = ""; + String mainTitle = isOverBook?"[Overbook]":"[Urgent]"; + helper.setSubject(mainTitle+"Waitlist Approval from Mobile CRM APP"+subTitle); // 标题 + helper.setFrom(mail_sender); // 来自 + + SimpleDateFormat sf = new SimpleDateFormat("dd-MMM-yyyy HH:mm"); + SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy"); + String RequestDate = sf.format(new Date()); + + String content2 = ""; + String tTime = RequestDate; + userId = !StringUtils.isEmpty(userId)?userId:""; + userName = !StringUtils.isEmpty(userName)?userName:""; + String tUser = userId+" "+userName; + String approvalStatus = EumnApprovalStatus.getApprovalStatusByDBValue(book.getApproveStatus()); + String changeProperty = ""; + String changeRoom = ""; + String changeCheckInDate = ""; + if(!Strings.CS.equals(viewBook.getPropertyName(), originBook.getPropertyName()) || + !Strings.CS.equals(viewBook.getRoom(), originBook.getRoom()) || + viewBook.getCheckinDate().getTime()!=originBook.getCheckoutDate().getTime()) { + changeProperty = viewBook.getPropertyName()!=null?viewBook.getPropertyName():""; + changeRoom = viewBook.getRoom()!=null?viewBook.getRoom():""; + changeCheckInDate = viewBook.getCheckinDate()!=null?format.format(viewBook.getCheckinDate()):""; + } + + + content2 += ""+ + "" + +approvalStatus+ + " "+ + "" + +originBook.getConfirmationNo()+ + " "+ + "" + +originBook.getPlayerId()+ + " " + + "" + +originBook.getMemberLastName()+ + " " + + "" + +(originBook.getMemberTier()!=null?originBook.getMemberTier():"")+ + " " + + "" + +(originBook.getPropertyName()!=null?originBook.getPropertyName():"")+ + " " + + "" + +(originBook.getRoom()!=null?originBook.getRoom():"")+ + " "+ + "" + +(originBook.getSharerName()!=null?originBook.getSharerName():"")+ + " "+ + "" + +"Extend"+ + " "+ + "" + +format.format(originBook.getCheckinDate())+ + " " + + "" + +format.format(originBook.getCheckoutDate())+ + " " + + "" + +changeProperty+ + " " + + "" + +changeRoom+ + " " + + "" + +changeCheckInDate+ + " " + + "" + +format.format(book.getCheckoutDate())+ + " " + + "" + +(viewBook.getBookerTeam()!=null?viewBook.getBookerTeam():"")+ + " " + + "" + +originBook.getCreatedBy()+ + " " + + "" + +originBook.getCreatedByName()+ + " " + + "" + +(book.getApprovalRemark()!=null?book.getApprovalRemark():"")+ + " " + + "" + +(book.getRemark()!=null?book.getRemark():"")+ + " " + + " "; + + content1 = content1.replace("{{tbody}}", content2); + content1 = content1.replace("{{ttime}}", tTime); + content1 = content1.replace("{{tuser}}", tUser); + helper.setText(content1,true); // 邮件内容,第二个参数指定发送的是HTML格式 + JSONObject emailJson = new JSONObject(); + emailJson.put("approvalStatus", approvalStatus); + emailJson.put("conf", book.getConfirmationNo()); + emailJson.put("memberId", book.getPlayerId()); + emailJson.put("memberName", book.getMemberLastName()); + emailJson.put("tier", originBook.getMemberTier()); + emailJson.put("property", originBook.getPropertyName()); + emailJson.put("roomType", originBook.getRoom()); + emailJson.put("type", "Extend"); + emailJson.put("checkin", format.format(originBook.getCheckinDate())); + emailJson.put("checkout", format.format(originBook.getCheckoutDate())); + emailJson.put("changeProperty", changeProperty); + emailJson.put("changeRoom", changeRoom); + emailJson.put("changeCheckin", changeCheckInDate); + emailJson.put("changeCheckout", format.format(book.getCheckoutDate())); + emailJson.put("bookerTeam", viewBook.getBookerTeam()); + emailJson.put("bookerId", originBook.getCreatedBy()); + emailJson.put("bookerName", originBook.getCreatedByName()); + emailJson.put("approvalRemark", book.getApprovalRemark()); + emailJson.put("remark", book.getRemark()); + + emailObj.setSendObject(emailJson.toJSONString()); + emailObj.setContent(content1); + emailObj.setSendTo(mail_to); + String[] mailToArr = StringUtils.split(mail_to,";"); + if(mailToArr.length>1) { + for (String str : mailToArr) { + helper.setTo(str); + try { + sender.send(mail); // 发送 + emailObj.setStatus(1); + } catch (Exception e) { + emailObj.setMessage("Send Email to "+str+" Failed:"+e.getMessage()); + emailObj.setStatus(0); + } + + } + }else { + helper.setTo(mail_to); + try { + sender.send(mail); // 发送 + emailObj.setStatus(1); + LogUtil.info(SendEmail.class, "---mgmEmail.sendApprovalExtendEmail--OK!"); + } catch (Exception e) { + emailObj.setMessage("Send Email to "+mail_to+" Failed:"+e.getMessage()); + emailObj.setStatus(0); + LogUtil.error(SendEmail.class, "---mgmEmail.sendApprovalExtendEmail--Failed!"+e.getMessage()); + } + } + + } catch (Exception e) { + LogUtil.error(SendEmail.class,"---mgmEmail.sendApprovalExtendEmail--Exception-->>"+e.getMessage()); + emailObj.setMessage(e.getMessage()); + emailObj.setStatus(0); + } + + return emailObj; + } + + public static Email sendCancelEmail(Bookings book,BookingsView bookingsView,Email emailObj,String userId,String userName,String emailTo) { + String content1 = cancelEmailTemp; + + try { + JavaMailSenderImpl sender = new JavaMailSenderImpl(); + if(StringUtils.isEmpty(mail_smtp_host)) { + mail_smtp_host = SysCommon.apiConfig.getHost_SMTP(); + } + mail_port = Integer.valueOf(SysCommon.apiConfig.getPort_SMTP()); + if(StringUtils.isEmpty(mail_sender)) { + mail_sender = SysCommon.apiConfig.getUsername_SMTP(); + } + if(StringUtils.isEmpty(mail_sender_password)) { + mail_sender_password = SysCommon.apiConfig.getPassword_SMTP(); + } + if(!StringUtils.isEmpty(emailTo)) { + mail_to = emailTo; + }else { + mail_to = SysCommon.apiConfig.getSend_to_SMTP(); + } + + sender.setHost(mail_smtp_host); + sender.setPort(mail_port); // 默认就是25 + sender.setUsername(mail_sender); + sender.setPassword(mail_sender_password);// + sender.setDefaultEncoding("UTF-8"); + + // 配置文件对象 + Properties props = new Properties(); + props.put("mail.smtp.auth", "false"); // 是否进行验证 + Session session = Session.getInstance(props); + sender.setSession(session); // 为发送器指定会话 + + MimeMessage mail = sender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(mail, true); + + String subTitle = ""; + + helper.setSubject("[Urgent] Modify Request from Mobile CRM APP"+subTitle); // 标题 + helper.setFrom(mail_sender); // 来自 + + SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + String RequestDate = sf.format(new Date()); + + String tTime = RequestDate; + userId = !StringUtils.isEmpty(userId)?userId:""; + userName = !StringUtils.isEmpty(userName)?userName:""; + String tUser = userId+" "+userName; + String content2 = ""; + userId = !StringUtils.isEmpty(userId)?userId:""; + userName = !StringUtils.isEmpty(userName)?userName:""; + String approvalStatus = EumnApprovalStatus.getApprovalStatusByDBValue(book.getApproveStatus()); + + content2 += ""+ + "" + +bookingsView.getConfirmationNo()+ + " "+ + "" + +approvalStatus+ + " "+ + "" + +bookingsView.getPlayerId()+ + " " + + "" + +bookingsView.getMemberLastName()+ + " " + + "" + +(bookingsView.getTier()!=null?bookingsView.getTier():"")+ + " " + + "" + +(bookingsView.getPropertyName()!=null?bookingsView.getPropertyName():"")+ + " " + + "" + +(bookingsView.getRoom()!=null?bookingsView.getRoom():"")+ + " "+ + "" + +(bookingsView.getSharerName()!=null?bookingsView.getSharerName():"")+ + " "+ + "" + +"Cancel"+ + " "+ + "" + +format.format(bookingsView.getCheckinDate())+ + " " + + "" + +format.format(bookingsView.getCheckoutDate())+ + " " + + "" + +book.getChangeCheckinDate()+ + " " + + "" + +book.getChangeCheckoutDate()+ + " "; + + + String content = "Please cancel Conf#"+book.getConfirmationNo()+" under "+book.getMemberLastName(); + + content1 = content1.replace("{{tbody}}", content2); + content1 = content1.replace("{{ttime}}", tTime); + content1 = content1.replace("{{tuser}}", tUser); + content1 = content1.replace("{{content}}", content); + helper.setText(content1,true); // 邮件内容,第二个参数指定发送的是HTML格式 + JSONObject emailJson = new JSONObject(); + emailJson.put("conf", book.getConfirmationNo()); + emailJson.put("memberId", book.getPlayerId()); + emailJson.put("memberName", book.getMemberLastName()); + + emailObj.setSendObject(emailJson.toJSONString()); + emailObj.setContent(content1); + emailObj.setSendTo(mail_to); + String[] mailToArr = StringUtils.split(mail_to,";"); + if(mailToArr.length>1) { + for (String str : mailToArr) { + helper.setTo(str); + try { + sender.send(mail); // 发送 + emailObj.setStatus(1); + } catch (Exception e) { + emailObj.setMessage("Send Email to "+str+" Failed:"+e.getMessage()); + emailObj.setStatus(0); + } + + } + }else { + helper.setTo(mail_to); + try { + sender.send(mail); // 发送 + emailObj.setStatus(1); + LogUtil.info(SendEmail.class, "---mgmEmail.sendCancelEmail--OK!"); + } catch (Exception e) { + emailObj.setMessage("Send Email to "+mail_to+" Failed:"+e.getMessage()); + emailObj.setStatus(0); + LogUtil.error(SendEmail.class, "---mgmEmail.sendCancelEmail--Failed!"+e.getMessage()); + } + } + + } catch (Exception e) { + LogUtil.error(SendEmail.class,"---mgmEmail.sendCancelEmail--Exception-->>"+e.getMessage()); + emailObj.setMessage(e.getMessage()); + emailObj.setStatus(0); + } + + return emailObj; + } + + public static boolean sendOtherBookingEmail(CfgEmailTemplate emailTemplate) { + Boolean status = false; + try { + JavaMailSenderImpl sender = new JavaMailSenderImpl(); + if(StringUtils.isEmpty(mail_smtp_host)) { + mail_smtp_host = SysCommon.apiConfig.getHost_SMTP(); + } + mail_port = Integer.valueOf(SysCommon.apiConfig.getPort_SMTP()); +// if(StringUtils.isEmpty(mail_sender)) { +// mail_sender = SysCommon.apiConfig.getUsername_SMTP(); +// } + if(StringUtils.isEmpty(mail_sender_password)) { + mail_sender_password = SysCommon.apiConfig.getPassword_SMTP(); + } + mail_to = SysCommon.apiConfig.getSend_to_SMTP(); + mail_sender = emailTemplate.getSender(); + sender.setHost(mail_smtp_host); + sender.setPort(mail_port); // 默认就是25 + sender.setUsername(mail_sender); + sender.setPassword(mail_sender_password);// + sender.setDefaultEncoding("UTF-8"); + + // 配置文件对象 + Properties props = new Properties(); + props.put("mail.smtp.auth", "false"); // 是否进行验证 + Session session = Session.getInstance(props); + sender.setSession(session); // 为发送器指定会话 + + MimeMessage mail = sender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(mail, true); + + String subject = emailTemplate.getSubject(); + subject = StringUtils.replace(subject, "[TODAY]",DateTimeUtil.getCurrentDate("dd MMM")); + helper.setSubject(subject); // 标题 + helper.setFrom(mail_sender); // 来自 + + helper.setCc(StringUtils.split(emailTemplate.getCc(),";")); + helper.setText(emailTemplate.getShowTemp(),true); // 邮件内容,第二个参数指定发送的是HTML格式 + String[] mailToArr = StringUtils.split(emailTemplate.getTo(),";"); + helper.setTo(mailToArr); + try { + sender.send(mail); // 发送 + LogUtil.info(SendEmail.class, "---mgmEmail.sendOtherBookingEmail--OK!"); + status=true; + } catch (Exception e) { + LogUtil.error(SendEmail.class, "send email failed:" + e.getMessage()); + status=false; + } + } catch (Exception e) { + LogUtil.error(SendEmail.class,"---mgmEmail.sendOtherBookingEmail--Exception-->>"+e.getMessage()); + status=false; + } + + return status; + } +} diff --git a/src/main/java/com/mgm/mcrm/common/utils/XMLBuliderUtil.java b/src/main/java/com/mgm/mcrm/common/utils/XMLBuliderUtil.java new file mode 100644 index 0000000..93e0d95 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/utils/XMLBuliderUtil.java @@ -0,0 +1,35 @@ +package com.mgm.mcrm.common.utils; + +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.security.AnyTypePermission; + + +/** + * XML工具类 + * + */ +public class XMLBuliderUtil { + public static Object toObject(Class clazz, String xmlStr) { + Object xmlObject = null; + ETLXstream xstream = new ETLXstream(); + xstream.setClassLoader(clazz.getClassLoader()); + xstream.processAnnotations(clazz); + xstream.autodetectAnnotations(true); + XStream.setupDefaultSecurity(xstream); + xstream.addPermission(AnyTypePermission.ANY); + xstream.allowTypes(new Class[]{clazz}); + xmlObject= xstream.fromXML(xmlStr); + return xmlObject; + } + + public static String removeXmlPrefix(String xmlContent, String[] prefixList) { + String returnContent = xmlContent.toString(); + if(prefixList!=null) { + for(String tag:prefixList) { + returnContent = returnContent.replace("<"+tag+":", "<"); + returnContent = returnContent.replace(" mockupResult(String mockupDataFile) { + BaseApiResponse result = new BaseApiResponse<>(); + try { + if(!Strings.CI.endsWith(mockupDataFile, ".json")) { + mockupDataFile=mockupDataFile+".json"; + } + String fileContent = SysCommon.loadResFileContentByPath(mockupDataFile,1); + JSONObject mockupConfig = JSONObject.parseObject(fileContent); + String dataClassName = mockupConfig.getString("dataClass"); + boolean isResList = false; + if(mockupConfig.containsKey("isList")) { + isResList = mockupConfig.getBooleanValue("isList"); + } + Class dataClass = null; + boolean isJSONOriginal=false; + if(Strings.CI.equals("JSON", dataClassName)) { + isJSONOriginal=true; + }else { + dataClass = Class.forName(dataClassName); + } + if(isResList) { + JSONArray dataObj = mockupConfig.getJSONArray("dataContent"); + if(isJSONOriginal) { + result.setData(dataObj); + }else { + List resObjs = JSONArray.parseArray(dataObj.toJSONString(), dataClass,Feature.SupportNonPublicField); + result.setData(resObjs); + } + }else { + JSONObject dataObj = mockupConfig.getJSONObject("dataContent"); + if(isJSONOriginal) { + result.setData(dataObj); + }else { + Object resObj = JSONObject.parseObject(dataObj.toJSONString(),dataClass,Feature.SupportNonPublicField); + result.setData(resObj); + } + } + result.setSuccess(true); + }catch(Exception err) { + result.setSuccess(false); + result.setMessage("Mockup failed with error:"+err.getMessage()); + } + return result; + } + + public static BaseApiResponse mockupFailedResult(String errorCode, String errorMsg) { + BaseApiResponse result = new BaseApiResponse<>(); + result.setSuccess(false); + result.setCode(errorCode); + result.setMessage(errorMsg); + return result; + } + +} 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 new file mode 100644 index 0000000..e6b790c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/common/utils/mockup/HttpUtilMockup.java @@ -0,0 +1,264 @@ +package com.mgm.mcrm.common.utils.mockup; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +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.LogUtil; + +public class HttpUtilMockup { + private static JSONArray mockupConfig=null; + private static JSONArray getMockupConfig() { + if(mockupConfig==null) { + try { + String fileContent = SysCommon.loadResFileContentByPath("\\mockup\\mgm_api_mockup_def.json",1); + mockupConfig = JSONArray.parseArray(fileContent); + if(mockupConfig==null) + mockupConfig = new JSONArray(); + }catch(Exception err) { + mockupConfig = new JSONArray(); + } + } + return mockupConfig; + } + + private static String findMockResultByLink(String requestLink,String requestContent) { + String result =""; + JSONArray configData = getMockupConfig(); + for(int i=0;i=0) { + resultIndex =matchIndex; + } + } + } + if(checkItem.containsKey("resultFiles")) { + JSONArray resultFiles = checkItem.getJSONArray("resultFiles") ; + if(resultFiles!=null && resultIndex operateList = new ArrayList(); + String[] andList = condiction.split("&&"); + for(int i=0;i0) { + operateList.add("&&"); + } + operateList.add(andList[i].trim()); + } + for(int i=0;i0) { + operateList.add(i,"||"); + i++; + } + if(j==0) { + operateList.set(i, orList[j].trim()); + i++; + }else { + operateList.add(i, orList[j].trim()); + i++; + } + } + } + } + String lastOperate = "AND"; + boolean isFirst =true; + for(int i=0;i0) { + int operIndex = express.indexOf("=="); + operate="=="; + valName1 = express.substring(0, operIndex).trim(); + valName2 =express.substring(operIndex+2).trim(); + }else if(express.indexOf(">=")>0) { + int operIndex = express.indexOf(">="); + operate=">="; + valName1 = express.substring(0, operIndex).trim(); + valName2 =express.substring(operIndex+2).trim(); + }else if(express.indexOf("<=")>0) { + int operIndex = express.indexOf("<="); + operate="<="; + valName1 = express.substring(0, operIndex).trim(); + valName2 =express.substring(operIndex+2).trim(); + }else if(express.indexOf(">")>0) { + int operIndex = express.indexOf(">"); + operate=">"; + valName1 = express.substring(0, operIndex).trim(); + valName2 =express.substring(operIndex+1).trim(); + }else if(express.indexOf("<")>0) { + int operIndex = express.indexOf("<"); + operate="<"; + valName1 = express.substring(0, operIndex).trim(); + valName2 =express.substring(operIndex+1).trim(); + } + if(!operate.isEmpty()) { + double numVal1 =0; + double numVal2 =0; + boolean isNum=true; + if(requestObj.containsKey(valName1)) { + try { + numVal1 = requestObj.getDoubleValue(valName1); + }catch(Exception err) { + isNum=false; + } + }else { + try { + numVal1 = Double.parseDouble(valName1); + }catch(Exception err) { + isNum=false; + } + } + if(isNum==true) { + if(requestObj.containsKey(valName2)) { + try { + numVal2 = requestObj.getDoubleValue(valName2); + }catch(Exception err) { + isNum=false; + } + }else { + try { + numVal2 = Double.parseDouble(valName2); + }catch(Exception err) { + isNum=false; + } + } + } + if(isNum==true) { + if(operate.equals("==")) { + result = (numVal1==numVal2); + }else if(operate.equals("<=")) { + result = (numVal1<=numVal2); + }else if(operate.equals(">=")) { + result = (numVal1>=numVal2); + }else if(operate.equals("<")) { + result = (numVal1")) { + result = (numVal1>numVal2); + } + }else { + String textVal1 = valName1; + String textVal2 = valName2; + if(requestObj.containsKey(valName1)) { + textVal1 = requestObj.getString(valName1); + } + if(requestObj.containsKey(valName2)) { + textVal2 = requestObj.getString(valName2); + } + if(operate.equals("==")) { + result = (textVal1.compareTo(textVal2)==0); + }else if(operate.equals("<=")) { + result = (textVal1.compareTo(textVal2)<=0); + }else if(operate.equals(">=")) { + result = (textVal1.compareTo(textVal2)>=0); + }else if(operate.equals("<")) { + result = (textVal1.compareTo(textVal2)<0); + }else if(operate.equals(">")) { + result = (textVal1.compareTo(textVal2)>0); + } + } + } + return result; + } + + //----- + public static HttpResponseResult processHttpRequest(HttpRequestDefine request) { + HttpResponseResult responseResult = new HttpResponseResult(); + SimpleDateFormat dtFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date requestTime = new Date(); + //-- + String requestUrl =request.getRequestUrl(); + responseResult.setRequestUrl(requestUrl); + responseResult.setRequestContent(request.getEntityContent()); + responseResult.setRequestTime(dtFormat.format(requestTime)); + responseResult.setRequestTimeVal(requestTime); + responseResult.setStatusCode(200); + String responseEntity = findMockResultByLink(requestUrl,request.getEntityContent()); + Date responseTime = new Date(); + responseResult.setResponseTime(dtFormat.format(responseTime)); + responseResult.setResponseTimeVal(responseTime); + responseResult.setResponseContent(responseEntity); + String logMsg = "Request:"+ JSON.toJSONString(request, true)+"\n"+"Response:"+JSON.toJSONString(responseResult); + LogUtil.info(HttpUtilMockup.class, logMsg); + return responseResult; + } + //------- +} diff --git a/src/main/java/com/mgm/mcrm/logging/controllers/SysLogAppController.java b/src/main/java/com/mgm/mcrm/logging/controllers/SysLogAppController.java new file mode 100644 index 0000000..3b46aff --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/controllers/SysLogAppController.java @@ -0,0 +1,65 @@ +package com.mgm.mcrm.logging.controllers; + +import java.util.Date; +import java.util.Map; + +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.logging.dtos.AppLogDto; +import com.mgm.mcrm.logging.services.SysLogAppService; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import com.mgm.mcrm.logging.models.SysLogApp; +import com.mgm.mcrm.common.utils.DateTimeUtil; +import com.mgm.mcrm.common.utils.NetworkUtil; + + +@RestController +@CrossOrigin(origins = "*") +@RequestMapping("/api") +public class SysLogAppController { + + @Resource + private SysLogAppService logService; + + @RequestMapping(value = "/system/write_log", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> writeAppLog(HttpServletRequest request, @RequestBody(required=true) AppLogDto appLogDto) { + String processMessage=""; + String errorCode=""; + BaseApiResponse result = new BaseApiResponse<>(); + + SysLogApp sysLogApp = new SysLogApp(); + String loginId = appLogDto.getLoginId(); + String eventCode = appLogDto.getEventCode(); + String transId = appLogDto.getTransId(); + String logDesc = appLogDto.getLogDesc(); + Integer tagSuccess = appLogDto.getTagSuccess(); + String requestBody = appLogDto.getRequestBody(); + String responseBody = appLogDto.getResponseBody(); + + Date now = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSSSS"); + sysLogApp.setLoginId(loginId); + sysLogApp.setTransId(transId); + sysLogApp.setLogDesc(logDesc); + sysLogApp.setTagSuccess(tagSuccess); + sysLogApp.setRequestBody(requestBody); + sysLogApp.setResponseBody(responseBody); + sysLogApp.setEventCode(eventCode); + sysLogApp.setOccurTime(now); + sysLogApp.setSortOccurtime(now.getTime()); + sysLogApp.setIpAddress(NetworkUtil.getClientIpAddr(request)); + + SysLogApp appLog = logService.save(sysLogApp); + + result.setSuccess(true); + result.setCode(errorCode); + result.setMessage(processMessage); + result.setData(appLog); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + +} diff --git a/src/main/java/com/mgm/mcrm/logging/controllers/SysLogConfirmController.java b/src/main/java/com/mgm/mcrm/logging/controllers/SysLogConfirmController.java new file mode 100644 index 0000000..137446a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/controllers/SysLogConfirmController.java @@ -0,0 +1,38 @@ +package com.mgm.mcrm.logging.controllers; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.mgm.mcrm.booking.models.BookingsView; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.logging.dtos.MobileConfirmLogRequest; +import com.mgm.mcrm.logging.models.SysLogMobileConfirm; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import com.mgm.mcrm.logging.services.SysLogConfirmService; + + +@RestController +@CrossOrigin(origins = "*") +@RequestMapping("/api") +public class SysLogConfirmController { + + @Resource + private SysLogConfirmService logService; + + @RequestMapping(value = "/app/log_confirm/save_confirm_log", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> getOperaBookingByConfirmationNo(HttpServletRequest request, + @RequestBody MobileConfirmLogRequest params) { + BaseApiResponse result =logService.saveConfirm(params); + result.setRequestData(params); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + +} diff --git a/src/main/java/com/mgm/mcrm/logging/controllers/SysLogDeviceTokenController.java b/src/main/java/com/mgm/mcrm/logging/controllers/SysLogDeviceTokenController.java new file mode 100644 index 0000000..60c93ca --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/controllers/SysLogDeviceTokenController.java @@ -0,0 +1,32 @@ +package com.mgm.mcrm.logging.controllers; + +import com.mgm.mcrm.logging.dtos.request.SaveDeviceTokenRequest; +import com.mgm.mcrm.logging.dtos.request.UpdateDeviceTokenRequest; +import com.mgm.mcrm.logging.dtos.response.SaveDeviceTokenResponse; +import com.mgm.mcrm.logging.services.SysLogDeviceTokenService; +import jakarta.annotation.Resource; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +@RequestMapping("/api/deviceToken") +public class SysLogDeviceTokenController { + + @Resource + private SysLogDeviceTokenService sysLogDeviceTokenService; + + @RequestMapping(value = "/save_device_token" , method = RequestMethod.POST, produces = "application/json;charset=UTF-8",consumes = MediaType.APPLICATION_JSON_VALUE) + public SaveDeviceTokenResponse saveDeviceToken(@RequestBody SaveDeviceTokenRequest request) throws Exception { + return sysLogDeviceTokenService.saveDeviceToken(request); + } + + @RequestMapping( value = "/update_device_token", method = RequestMethod.POST, produces = "application/json;charset=UTF-8",consumes = MediaType.APPLICATION_JSON_VALUE) + public Boolean updateDeviceToken(@RequestBody UpdateDeviceTokenRequest request) throws Exception { + return sysLogDeviceTokenService.updateDeviceToken(request); + } + +} diff --git a/src/main/java/com/mgm/mcrm/logging/dtos/AppLogDto.java b/src/main/java/com/mgm/mcrm/logging/dtos/AppLogDto.java new file mode 100644 index 0000000..f827f7f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/dtos/AppLogDto.java @@ -0,0 +1,15 @@ +package com.mgm.mcrm.logging.dtos; + +import lombok.Data; + +@Data +public class AppLogDto { + + private String loginId; + private String eventCode; + private String transId; + private String logDesc; + private Integer tagSuccess; + private String requestBody; + private String responseBody; +} diff --git a/src/main/java/com/mgm/mcrm/logging/dtos/MobileConfirmLogRequest.java b/src/main/java/com/mgm/mcrm/logging/dtos/MobileConfirmLogRequest.java new file mode 100644 index 0000000..f8a85f4 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/dtos/MobileConfirmLogRequest.java @@ -0,0 +1,9 @@ +package com.mgm.mcrm.logging.dtos; + +import lombok.Data; + +@Data +public class MobileConfirmLogRequest { + private String userId; + private String userName; +} diff --git a/src/main/java/com/mgm/mcrm/logging/dtos/request/SaveDeviceTokenRequest.java b/src/main/java/com/mgm/mcrm/logging/dtos/request/SaveDeviceTokenRequest.java new file mode 100644 index 0000000..c5067c4 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/dtos/request/SaveDeviceTokenRequest.java @@ -0,0 +1,11 @@ +package com.mgm.mcrm.logging.dtos.request; + + +import lombok.Data; + +@Data +public class SaveDeviceTokenRequest { + private String deviceToken; + private String userId; + private Integer useLanguage; +} diff --git a/src/main/java/com/mgm/mcrm/logging/dtos/request/UpdateDeviceTokenRequest.java b/src/main/java/com/mgm/mcrm/logging/dtos/request/UpdateDeviceTokenRequest.java new file mode 100644 index 0000000..bdf8ac4 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/dtos/request/UpdateDeviceTokenRequest.java @@ -0,0 +1,10 @@ +package com.mgm.mcrm.logging.dtos.request; + + +import lombok.Data; + +@Data +public class UpdateDeviceTokenRequest { + private String userId; + private Integer useLanguage; +} diff --git a/src/main/java/com/mgm/mcrm/logging/dtos/response/SaveDeviceTokenResponse.java b/src/main/java/com/mgm/mcrm/logging/dtos/response/SaveDeviceTokenResponse.java new file mode 100644 index 0000000..853444b --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/dtos/response/SaveDeviceTokenResponse.java @@ -0,0 +1,9 @@ +package com.mgm.mcrm.logging.dtos.response; + +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import lombok.Data; + +@Data +public class SaveDeviceTokenResponse extends BaseApiResponse { + private int id; +} diff --git a/src/main/java/com/mgm/mcrm/logging/dtos/response/UpdateDeviceTokenResponse.java b/src/main/java/com/mgm/mcrm/logging/dtos/response/UpdateDeviceTokenResponse.java new file mode 100644 index 0000000..874be64 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/dtos/response/UpdateDeviceTokenResponse.java @@ -0,0 +1,9 @@ +package com.mgm.mcrm.logging.dtos.response; + +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import lombok.Data; + +@Data +public class UpdateDeviceTokenResponse extends BaseApiResponse { + private Boolean isSuccess; +} diff --git a/src/main/java/com/mgm/mcrm/logging/models/SysLogApp.java b/src/main/java/com/mgm/mcrm/logging/models/SysLogApp.java new file mode 100644 index 0000000..a2c251d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/models/SysLogApp.java @@ -0,0 +1,114 @@ +package com.mgm.mcrm.logging.models; + +import java.io.Serializable; +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; + +@Entity +@Table(name="sys_log_app") +public class SysLogApp implements Serializable { + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="event_code") + private String eventCode; + @Column(name="trans_id") + private String transId; + @Column(name="occur_time") + private Date occurTime; + @Column(name="login_id") + private String loginId; + @Column(name="log_desc") + private String logDesc; + @Column(name="request_body") + private String requestBody; + @Column(name="response_body") + private String responseBody; + @Column(name="tag_success") + private Integer tagSuccess; + @Column(name="sort_occurtime") + private Long sortOccurtime; + @Column(name="ip_address") + private String ipAddress; + @Column(name="computer_name") + private String computerName; + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public String getEventCode() { + return eventCode; + } + public void setEventCode(String eventCode) { + this.eventCode = eventCode; + } + public String getTransId() { + return transId; + } + public void setTransId(String transId) { + this.transId = transId; + } + public Date getOccurTime() { + return occurTime; + } + public void setOccurTime(Date occurTime) { + this.occurTime = occurTime; + } + public String getLoginId() { + return loginId; + } + public void setLoginId(String loginId) { + this.loginId = loginId; + } + public String getLogDesc() { + return logDesc; + } + public void setLogDesc(String logDesc) { + this.logDesc = logDesc; + } + public String getRequestBody() { + return requestBody; + } + public void setRequestBody(String requestBody) { + this.requestBody = requestBody; + } + public String getResponseBody() { + return responseBody; + } + public void setResponseBody(String responseBody) { + this.responseBody = responseBody; + } + public Integer getTagSuccess() { + return tagSuccess; + } + public void setTagSuccess(Integer tagSuccess) { + this.tagSuccess = tagSuccess; + } + public Long getSortOccurtime() { + return sortOccurtime; + } + public void setSortOccurtime(Long sortOccurtime) { + this.sortOccurtime = sortOccurtime; + } + public String getIpAddress() { + return ipAddress; + } + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + public String getComputerName() { + return computerName; + } + public void setComputerName(String computerName) { + this.computerName = computerName; + } +} diff --git a/src/main/java/com/mgm/mcrm/logging/models/SysLogBooking.java b/src/main/java/com/mgm/mcrm/logging/models/SysLogBooking.java new file mode 100644 index 0000000..6f71335 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/models/SysLogBooking.java @@ -0,0 +1,101 @@ +package com.mgm.mcrm.logging.models; + +import java.io.Serializable; +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; + +@Entity +@Table(name="sys_log_booking") +public class SysLogBooking implements Serializable { + //fields in table + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="book_id") + private Long bookId; + @Column(name="event_code") + private String eventCode; + @Column(name="occur_time") + private Date occurTime; + @Column(name="login_id") + private String loginId; + @Column(name="login_name") + private String loginName; + @Column(name="change_from") + private String changeFrom; + @Column(name="change_to") + private String changeTo; + @Column(name="sort_occurtime") + private Long sortOccurtime; + @Column(name="ip_address") + private String ipAddress; + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public Long getBookId() { + return bookId; + } + public void setBookId(Long bookId) { + this.bookId = bookId; + } + public String getEventCode() { + return eventCode; + } + public void setEventCode(String eventCode) { + this.eventCode = eventCode; + } + public Date getOccurTime() { + return occurTime; + } + public void setOccurTime(Date occurTime) { + this.occurTime = occurTime; + } + public String getLoginId() { + return loginId; + } + public void setLoginId(String loginId) { + this.loginId = loginId; + } + public String getLoginName() { + return loginName; + } + public void setLoginName(String loginName) { + this.loginName = loginName; + } + public String getChangeFrom() { + return changeFrom; + } + public void setChangeFrom(String changeFrom) { + this.changeFrom = changeFrom; + } + public String getChangeTo() { + return changeTo; + } + public void setChangeTo(String changeTo) { + this.changeTo = changeTo; + } + public Long getSortOccurtime() { + return sortOccurtime; + } + public void setSortOccurtime(Long sortOccurtime) { + this.sortOccurtime = sortOccurtime; + } + public String getIpAddress() { + return ipAddress; + } + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/logging/models/SysLogDeviceToken.java b/src/main/java/com/mgm/mcrm/logging/models/SysLogDeviceToken.java new file mode 100644 index 0000000..1338048 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/models/SysLogDeviceToken.java @@ -0,0 +1,39 @@ +package com.mgm.mcrm.logging.models; + +import jakarta.persistence.*; +import lombok.Data; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import java.util.Date; + +@Data +@Entity +@Table(name = "sys_log_device_token", + indexes = { + @Index(name = "idx_device_token", columnList = "deviceToken") + }) +public class SysLogDeviceToken { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Integer id; + + @Column(name = "user_id", unique = true, nullable = false, length = 64) + private String userId; + + @Column(name = "device_token", length = 255) + private String deviceToken; + + @CreationTimestamp + @Column(name = "created_at", updatable = false) + private Date createdAt; + + @UpdateTimestamp + @Column(name = "updated_at") + private Date updatedAt; + + @Column(name = "use_language_type") + private Integer useLanguageType; +} \ No newline at end of file diff --git a/src/main/java/com/mgm/mcrm/logging/models/SysLogETA.java b/src/main/java/com/mgm/mcrm/logging/models/SysLogETA.java new file mode 100644 index 0000000..a40723e --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/models/SysLogETA.java @@ -0,0 +1,91 @@ +package com.mgm.mcrm.logging.models; + +import jakarta.persistence.*; +import java.util.Date; + +@Entity +@Table(name = "sys_log_eta") +public class SysLogETA { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "input_date_time") + private String inputDateTime; + + @Column(name = "player_id") + private String playerId; + + @Column(name = "user_id") + private String userId; + + @Column(name = "created_at") + private Date createdAt; + + @Column(name = "updated_at") + private Date updatedAt; + + @Column(name = "status") + private Integer status; + + public SysLogETA() { + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getInputDateTime() { + return inputDateTime; + } + + public void setInputDateTime(String inputDateTime) { + this.inputDateTime = inputDateTime; + } + + 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 Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/src/main/java/com/mgm/mcrm/logging/models/SysLogLogin.java b/src/main/java/com/mgm/mcrm/logging/models/SysLogLogin.java new file mode 100644 index 0000000..d049dd3 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/models/SysLogLogin.java @@ -0,0 +1,115 @@ +package com.mgm.mcrm.logging.models; + +import java.io.Serializable; +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; + +@Entity +@Table(name="sys_log_login") +public class SysLogLogin implements Serializable { + //fields in table + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="event_code") + private String eventCode; + @Column(name="trans_id") + private String transId; + @Column(name="occur_time") + private Date occurTime; + @Column(name="login_id") + private String loginId; + @Column(name="log_desc") + private String logDesc; + @Column(name="request_body") + private String requestBody; + @Column(name="response_body") + private String responseBody; + @Column(name="tag_success") + private Integer tagSuccess; + @Column(name="sort_occurtime") + private Long sortOccurtime; + @Column(name="ip_address") + private String ipAddress; + @Column(name="computer_name") + private String computerName; + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public String getEventCode() { + return eventCode; + } + public void setEventCode(String eventCode) { + this.eventCode = eventCode; + } + public String getTransId() { + return transId; + } + public void setTransId(String transId) { + this.transId = transId; + } + public Date getOccurTime() { + return occurTime; + } + public void setOccurTime(Date occurTime) { + this.occurTime = occurTime; + } + public String getLoginId() { + return loginId; + } + public void setLoginId(String loginId) { + this.loginId = loginId; + } + public String getLogDesc() { + return logDesc; + } + public void setLogDesc(String logDesc) { + this.logDesc = logDesc; + } + public String getRequestBody() { + return requestBody; + } + public void setRequestBody(String requestBody) { + this.requestBody = requestBody; + } + public String getResponseBody() { + return responseBody; + } + public void setResponseBody(String responseBody) { + this.responseBody = responseBody; + } + public Integer getTagSuccess() { + return tagSuccess; + } + public void setTagSuccess(Integer tagSuccess) { + this.tagSuccess = tagSuccess; + } + public Long getSortOccurtime() { + return sortOccurtime; + } + public void setSortOccurtime(Long sortOccurtime) { + this.sortOccurtime = sortOccurtime; + } + public String getIpAddress() { + return ipAddress; + } + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + public String getComputerName() { + return computerName; + } + public void setComputerName(String computerName) { + this.computerName = computerName; + } +} diff --git a/src/main/java/com/mgm/mcrm/logging/models/SysLogLoginIp.java b/src/main/java/com/mgm/mcrm/logging/models/SysLogLoginIp.java new file mode 100644 index 0000000..10c1158 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/models/SysLogLoginIp.java @@ -0,0 +1,94 @@ +package com.mgm.mcrm.logging.models; + +import jakarta.persistence.*; +import java.io.Serializable; +import java.util.Date; +import java.util.Objects; + +@Entity +@Table(name="sys_log_login_ip") +public class SysLogLoginIp implements Serializable { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "ip") + private String ip; + + @Column(name = "try_times") + private Integer tryTimes; + + @Column(name = "last_login_times") + private Date lastLoginTimes; + + @Column(name = "ban_until") + private Date banUntil; + + public SysLogLoginIp() {} + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public Integer getTryTimes() { + return tryTimes; + } + + public void setTryTimes(Integer tryTimes) { + this.tryTimes = tryTimes; + } + + public Date getLastLoginTimes() { + return lastLoginTimes; + } + + public void setLastLoginTimes(Date lastLoginTimes) { + this.lastLoginTimes = lastLoginTimes; + } + + public Date getBanUntil() { + return banUntil; + } + + public void setBanUntil(Date banUntil) { + this.banUntil = banUntil; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SysLogLoginIp that = (SysLogLoginIp) o; + return Objects.equals(id, that.id) && Objects.equals(ip, that.ip) && Objects.equals(tryTimes, that.tryTimes) && Objects.equals(lastLoginTimes, that.lastLoginTimes) && Objects.equals(banUntil, that.banUntil); + } + + @Override + public int hashCode() { + return Objects.hash(id, ip, tryTimes, lastLoginTimes, banUntil); + } + + @Override + public String toString() { + return "SysLogLoginIp{" + + "id=" + id + + ", ip='" + ip + '\'' + + ", tryTimes=" + tryTimes + + ", lastLoginTimes=" + lastLoginTimes + + ", banUntil=" + banUntil + + '}'; + } +} diff --git a/src/main/java/com/mgm/mcrm/logging/models/SysLogMobileConfirm.java b/src/main/java/com/mgm/mcrm/logging/models/SysLogMobileConfirm.java new file mode 100644 index 0000000..9b05613 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/models/SysLogMobileConfirm.java @@ -0,0 +1,52 @@ +package com.mgm.mcrm.logging.models; + +import java.io.Serializable; +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; + +@Entity +@Table(name="sys_log_confirm") +public class SysLogMobileConfirm implements Serializable { + //fields in table + @Id + @Column(name="id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="user_id") + private String userId; + @Column(name="user_name") + private String userName; + @Column(name="confirm_date") + private Date confirmDate; + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public String getUserId() { + return userId; + } + public void setUserId(String userId) { + this.userId = userId; + } + public String getUserName() { + return userName; + } + public void setUserName(String userName) { + this.userName = userName; + } + public Date getConfirmDate() { + return confirmDate; + } + public void setConfirmDate(Date confirmDate) { + this.confirmDate = confirmDate; + } + +} diff --git a/src/main/java/com/mgm/mcrm/logging/models/SysLogOperation.java b/src/main/java/com/mgm/mcrm/logging/models/SysLogOperation.java new file mode 100644 index 0000000..7a6785c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/models/SysLogOperation.java @@ -0,0 +1,115 @@ +package com.mgm.mcrm.logging.models; + +import java.io.Serializable; +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; + +@Entity +@Table(name="sys_log_operation") +public class SysLogOperation implements Serializable { + //fields in table + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="event_code") + private String eventCode; + @Column(name="trans_id") + private String transId; + @Column(name="occur_time") + private Date occurTime; + @Column(name="login_id") + private String loginId; + @Column(name="log_desc") + private String logDesc; + @Column(name="request_body") + private String requestBody; + @Column(name="response_body") + private String responseBody; + @Column(name="tag_success") + private Integer tagSuccess; + @Column(name="sort_occurtime") + private Long sortOccurtime; + @Column(name="ip_address") + private String ipAddress; + @Column(name="computer_name") + private String computerName; + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public String getEventCode() { + return eventCode; + } + public void setEventCode(String eventCode) { + this.eventCode = eventCode; + } + public String getTransId() { + return transId; + } + public void setTransId(String transId) { + this.transId = transId; + } + public Date getOccurTime() { + return occurTime; + } + public void setOccurTime(Date occurTime) { + this.occurTime = occurTime; + } + public String getLoginId() { + return loginId; + } + public void setLoginId(String loginId) { + this.loginId = loginId; + } + public String getLogDesc() { + return logDesc; + } + public void setLogDesc(String logDesc) { + this.logDesc = logDesc; + } + public String getRequestBody() { + return requestBody; + } + public void setRequestBody(String requestBody) { + this.requestBody = requestBody; + } + public String getResponseBody() { + return responseBody; + } + public void setResponseBody(String responseBody) { + this.responseBody = responseBody; + } + public Integer getTagSuccess() { + return tagSuccess; + } + public void setTagSuccess(Integer tagSuccess) { + this.tagSuccess = tagSuccess; + } + public Long getSortOccurtime() { + return sortOccurtime; + } + public void setSortOccurtime(Long sortOccurtime) { + this.sortOccurtime = sortOccurtime; + } + public String getIpAddress() { + return ipAddress; + } + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + public String getComputerName() { + return computerName; + } + public void setComputerName(String computerName) { + this.computerName = computerName; + } +} diff --git a/src/main/java/com/mgm/mcrm/logging/repositories/SysLogAppDao.java b/src/main/java/com/mgm/mcrm/logging/repositories/SysLogAppDao.java new file mode 100644 index 0000000..8970de5 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/repositories/SysLogAppDao.java @@ -0,0 +1,30 @@ +package com.mgm.mcrm.logging.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import com.mgm.mcrm.logging.models.SysLogApp; + + +public interface SysLogAppDao extends JpaRepository { + SysLogApp findById(long id); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + + public interface OperationEvent{ + Integer getId(); + String getEventCode(); + Integer getCategory(); + } + + @Query(value="select id as id, event_code as eventCode, event_desc as eventDesc, category " + + " from sys_log_type where category=1",nativeQuery=true) + List listOperationEvent(); +} diff --git a/src/main/java/com/mgm/mcrm/logging/repositories/SysLogBookingDao.java b/src/main/java/com/mgm/mcrm/logging/repositories/SysLogBookingDao.java new file mode 100644 index 0000000..86671eb --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/repositories/SysLogBookingDao.java @@ -0,0 +1,22 @@ +package com.mgm.mcrm.logging.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; + +import com.mgm.mcrm.logging.models.SysLogBooking; + + + +public interface SysLogBookingDao extends JpaRepository { + SysLogBooking findById(long id); + List findByBookIdOrderByOccurTimeDesc(long bookId); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + +} diff --git a/src/main/java/com/mgm/mcrm/logging/repositories/SysLogConfirmDao.java b/src/main/java/com/mgm/mcrm/logging/repositories/SysLogConfirmDao.java new file mode 100644 index 0000000..b41f4eb --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/repositories/SysLogConfirmDao.java @@ -0,0 +1,20 @@ +package com.mgm.mcrm.logging.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; + +import com.mgm.mcrm.logging.models.SysLogMobileConfirm; + + +public interface SysLogConfirmDao extends JpaRepository { + SysLogMobileConfirm findById(long id); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); + +} diff --git a/src/main/java/com/mgm/mcrm/logging/repositories/SysLogDeviceTokenDao.java b/src/main/java/com/mgm/mcrm/logging/repositories/SysLogDeviceTokenDao.java new file mode 100644 index 0000000..97eb77d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/repositories/SysLogDeviceTokenDao.java @@ -0,0 +1,13 @@ +package com.mgm.mcrm.logging.repositories; + +import com.mgm.mcrm.logging.models.SysLogDeviceToken; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface SysLogDeviceTokenDao extends JpaRepository { + + SysLogDeviceToken findByUserId(String bookerId); + + void deleteByUserId(String userId); +} diff --git a/src/main/java/com/mgm/mcrm/logging/repositories/SysLogETADao.java b/src/main/java/com/mgm/mcrm/logging/repositories/SysLogETADao.java new file mode 100644 index 0000000..17aa35b --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/repositories/SysLogETADao.java @@ -0,0 +1,10 @@ +package com.mgm.mcrm.logging.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; +import com.mgm.mcrm.logging.models.SysLogETA; + +import java.util.List; + +public interface SysLogETADao extends JpaRepository { + +} diff --git a/src/main/java/com/mgm/mcrm/logging/repositories/SysLogLoginDao.java b/src/main/java/com/mgm/mcrm/logging/repositories/SysLogLoginDao.java new file mode 100644 index 0000000..e9b08d9 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/repositories/SysLogLoginDao.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.logging.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; + +import com.mgm.mcrm.logging.models.SysLogLogin; + + +public interface SysLogLoginDao extends JpaRepository { + SysLogLogin findById(long id); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); +} diff --git a/src/main/java/com/mgm/mcrm/logging/repositories/SysLogLoginIpDao.java b/src/main/java/com/mgm/mcrm/logging/repositories/SysLogLoginIpDao.java new file mode 100644 index 0000000..c3237ea --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/repositories/SysLogLoginIpDao.java @@ -0,0 +1,28 @@ +package com.mgm.mcrm.logging.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import com.mgm.mcrm.logging.models.SysLogLoginIp; + +import java.util.Date; +import java.util.List; + +public interface SysLogLoginIpDao extends JpaRepository { + + + SysLogLoginIp findByIpAndLastLoginTimesBetween(String ip, Date start, Date end); + + // 查找已过期的封禁记录 + @Query("SELECT s FROM SysLogLoginIp s WHERE s.banUntil IS NOT NULL AND s.banUntil < CURRENT_TIMESTAMP") + List findExpiredBans(); + + // 查找今日被封禁的所有的ip记录 + @Query("SELECT s FROM SysLogLoginIp s " + + "WHERE s.banUntil IS NOT NULL " + + "AND s.banUntil > CURRENT_TIMESTAMP " + + "AND s.lastLoginTimes >= :start " + + "AND s.lastLoginTimes < :end") + List findTodayBannedIps(@Param("start") Date start, + @Param("end") Date end); +} diff --git a/src/main/java/com/mgm/mcrm/logging/repositories/SysLogOperationDao.java b/src/main/java/com/mgm/mcrm/logging/repositories/SysLogOperationDao.java new file mode 100644 index 0000000..d8ab3ec --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/repositories/SysLogOperationDao.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.logging.repositories; + +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; + +import com.mgm.mcrm.logging.models.SysLogOperation; + + +public interface SysLogOperationDao extends JpaRepository { + SysLogOperation findById(long id); + List findAll(Specification spec,Sort sort); + List findAll(Specification spec); + Page findAll(Specification spec, Pageable pageable); +} diff --git a/src/main/java/com/mgm/mcrm/logging/services/SysLogAppService.java b/src/main/java/com/mgm/mcrm/logging/services/SysLogAppService.java new file mode 100644 index 0000000..4d77e37 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/services/SysLogAppService.java @@ -0,0 +1,18 @@ +package com.mgm.mcrm.logging.services; + +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import com.mgm.mcrm.logging.models.SysLogApp; +import com.mgm.mcrm.logging.repositories.SysLogAppDao; + +@Service +public class SysLogAppService { + + @Resource + private SysLogAppDao SysLogAppDao; + + public SysLogApp save(SysLogApp obj) { + return SysLogAppDao.save(obj); + } +} diff --git a/src/main/java/com/mgm/mcrm/logging/services/SysLogBookingService.java b/src/main/java/com/mgm/mcrm/logging/services/SysLogBookingService.java new file mode 100644 index 0000000..94b66da --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/services/SysLogBookingService.java @@ -0,0 +1,95 @@ +package com.mgm.mcrm.logging.services; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import com.mgm.mcrm.authorization.dtos.LoginUserInfo; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import com.mgm.mcrm.logging.models.SysLogBooking; +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.common.dtos.EumnApprovalStatus; +import com.mgm.mcrm.common.utils.NetworkUtil; +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.logging.repositories.SysLogBookingDao; + +@Service +public class SysLogBookingService { + + @Resource + private SysLogBookingDao sysLogBookingDao; + + public SysLogBooking save(SysLogBooking obj) { + return sysLogBookingDao.save(obj); + } + + public List saveLogBooking(List books, HttpServletRequest request, + String changeFrom, String changeTo, String eventCode, String type) { + List addList = new ArrayList<>(); + + if(!books.isEmpty()) { + for(Bookings book :books) { + SysLogBooking sysLogBooking = new SysLogBooking(); + + if(request!=null) { + LoginUserInfo userInfo =SysCommon.parseUserFromToken(request); + if (userInfo != null) { + sysLogBooking.setLoginId(userInfo.getLoginId()); + sysLogBooking.setLoginName(userInfo.getLoginId()); + }else { + if(!StringUtils.isEmpty(book.getUpdatedBy())) { + sysLogBooking.setLoginId(book.getUpdatedBy()); + sysLogBooking.setLoginName(book.getUpdatedBy()); + }else if(!StringUtils.isEmpty(book.getCreatedBy())) { + sysLogBooking.setLoginId(book.getCreatedBy()); + sysLogBooking.setLoginName(book.getCreatedByName()); + }else{ + sysLogBooking.setLoginId(""); + sysLogBooking.setLoginName(""); + } + } + }else { + if(!StringUtils.isEmpty(book.getUpdatedBy())) { + sysLogBooking.setLoginId(book.getUpdatedBy()); + sysLogBooking.setLoginName(book.getUpdatedBy()); + }else if(!StringUtils.isEmpty(book.getCreatedBy())) { + sysLogBooking.setLoginId(book.getCreatedBy()); + sysLogBooking.setLoginName(book.getCreatedByName()); + }else{ + sysLogBooking.setLoginId(""); + sysLogBooking.setLoginName(""); + } + } + + + Date now = new Date(); + sysLogBooking.setBookId(book.getId()); + sysLogBooking.setOccurTime(now); + sysLogBooking.setSortOccurtime(now.getTime()); + if(request!=null) { + sysLogBooking.setIpAddress(NetworkUtil.getClientIpAddr(request)); + } + sysLogBooking.setEventCode(eventCode); + if("approve_status".equals(type)) { + sysLogBooking.setChangeFrom(EumnApprovalStatus.getApprovalStatusByDBValue(book.getApproveStatus())); + }else { + sysLogBooking.setChangeFrom(changeFrom); + } + + sysLogBooking.setChangeTo(changeTo); + addList.add(sysLogBooking); + + } + sysLogBookingDao.saveAll(addList); + } + + return addList; + + } + +} diff --git a/src/main/java/com/mgm/mcrm/logging/services/SysLogConfirmService.java b/src/main/java/com/mgm/mcrm/logging/services/SysLogConfirmService.java new file mode 100644 index 0000000..92d3408 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/services/SysLogConfirmService.java @@ -0,0 +1,38 @@ +package com.mgm.mcrm.logging.services; + + +import java.util.Date; +import java.util.Map; + +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.logging.dtos.MobileConfirmLogRequest; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import com.mgm.mcrm.logging.models.SysLogMobileConfirm; +import com.mgm.mcrm.logging.repositories.SysLogConfirmDao; + +@Service +public class SysLogConfirmService { + + @Resource + private SysLogConfirmDao sysLogConfirmDao; + + public BaseApiResponse saveConfirm(MobileConfirmLogRequest params) { + BaseApiResponse processResult= new BaseApiResponse<>(); + String userId = params.getUserId(); + String userName = params.getUserName(); + Date occurTime = new Date(System.currentTimeMillis()); + SysLogMobileConfirm confirmLog = new SysLogMobileConfirm(); + + confirmLog.setUserId(userId); + confirmLog.setUserName(userName); + confirmLog.setConfirmDate(occurTime); + + sysLogConfirmDao.save(confirmLog); + processResult.setData(confirmLog); + processResult.setSuccess(true); + return processResult; + } + +} diff --git a/src/main/java/com/mgm/mcrm/logging/services/SysLogDeviceTokenService.java b/src/main/java/com/mgm/mcrm/logging/services/SysLogDeviceTokenService.java new file mode 100644 index 0000000..491c4ed --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/services/SysLogDeviceTokenService.java @@ -0,0 +1,74 @@ +package com.mgm.mcrm.logging.services; + +import com.mgm.mcrm.common.utils.LogUtil; +import com.mgm.mcrm.logging.dtos.request.SaveDeviceTokenRequest; +import com.mgm.mcrm.logging.dtos.request.UpdateDeviceTokenRequest; +import com.mgm.mcrm.logging.dtos.response.SaveDeviceTokenResponse; +import com.mgm.mcrm.logging.models.SysLogDeviceToken; +import com.mgm.mcrm.logging.repositories.SysLogDeviceTokenDao; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; + +@Service +public class SysLogDeviceTokenService { + @Resource + private SysLogDeviceTokenDao sysLogDeviceTokenDao; + + public SaveDeviceTokenResponse saveDeviceToken(SaveDeviceTokenRequest request) { + + + SaveDeviceTokenResponse response = new SaveDeviceTokenResponse(); + Date now = new Date(); + + //判断当前User是否已经有DeviceId存在 + SysLogDeviceToken existing = sysLogDeviceTokenDao.findByUserId(request.getUserId()); + SysLogDeviceToken sysLogDeviceToken; + + if (existing == null) { + LogUtil.info(SysLogDeviceTokenService.class,"Save New DeviceToken,UserId = " + request.getUserId()+" DeviceToken = " + request.getDeviceToken()); + + //不存在插入新数据 + sysLogDeviceToken = new SysLogDeviceToken(); + sysLogDeviceToken.setUserId(request.getUserId()); + sysLogDeviceToken.setDeviceToken(request.getDeviceToken()); + sysLogDeviceToken.setUseLanguageType(request.getUseLanguage()); + sysLogDeviceToken.setCreatedAt(now); + }else{ + LogUtil.info(SysLogDeviceTokenService.class,"Update DeviceToken,UserId = " + request.getUserId()+" DeviceToken = " + request.getDeviceToken()); + + //存在更新旧数据 + sysLogDeviceToken = existing; + sysLogDeviceToken.setDeviceToken(request.getDeviceToken()); + sysLogDeviceToken.setUseLanguageType(request.getUseLanguage()); + sysLogDeviceToken.setUpdatedAt(now); + } + + SysLogDeviceToken save = sysLogDeviceTokenDao.save(sysLogDeviceToken); + response.setId(save.getId()); + response.setSuccess(Boolean.TRUE); + return response; + } + + public Boolean updateDeviceToken(UpdateDeviceTokenRequest request) { + + LogUtil.info(SysLogDeviceTokenService.class,"UpdateDeviceToken,UserId = " + request.getUserId()+" UseLanguage = " + request.getUseLanguage()); + + Date now = new Date(); + + //判断当前User是否已经有DeviceId存在 + SysLogDeviceToken existing = sysLogDeviceTokenDao.findByUserId(request.getUserId()); + + if (existing != null) { + //只有在存在的时候才更新DeviceToken + existing.setUseLanguageType(request.getUseLanguage()); + existing.setUpdatedAt(now); + sysLogDeviceTokenDao.save(existing); + } + + return true; + } + +} diff --git a/src/main/java/com/mgm/mcrm/logging/services/SysLogETAService.java b/src/main/java/com/mgm/mcrm/logging/services/SysLogETAService.java new file mode 100644 index 0000000..ec66b53 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/services/SysLogETAService.java @@ -0,0 +1,18 @@ +package com.mgm.mcrm.logging.services; + +import com.mgm.mcrm.logging.models.SysLogETA; +import org.springframework.stereotype.Service; +import com.mgm.mcrm.logging.repositories.SysLogETADao; + +import jakarta.annotation.Resource; + +@Service +public class SysLogETAService { + + @Resource + private SysLogETADao sysLogETADao; + + public void save(SysLogETA sysLogETA) { + sysLogETADao.save(sysLogETA); + } +} diff --git a/src/main/java/com/mgm/mcrm/logging/services/SysLogLoginIpService.java b/src/main/java/com/mgm/mcrm/logging/services/SysLogLoginIpService.java new file mode 100644 index 0000000..baf1496 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/services/SysLogLoginIpService.java @@ -0,0 +1,56 @@ +package com.mgm.mcrm.logging.services; + +import com.mgm.mcrm.logging.models.SysLogLoginIp; +import org.springframework.stereotype.Service; +import com.mgm.mcrm.logging.repositories.SysLogLoginIpDao; + +import jakarta.annotation.Resource; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +@Service +public class SysLogLoginIpService { + + @Resource + private SysLogLoginIpDao sysLogLoginIpDao; + + public void save(SysLogLoginIp sysLogLoginIp) { + sysLogLoginIpDao.save(sysLogLoginIp); + } + + // 查询今天记录 + public SysLogLoginIp findTodayRecordByIp(String ip) { + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + Date startOfToday = calendar.getTime(); + + calendar.add(Calendar.DAY_OF_MONTH, 1); + Date startOfTomorrow = calendar.getTime(); + + return sysLogLoginIpDao.findByIpAndLastLoginTimesBetween(ip, startOfToday, startOfTomorrow); + } + + /** 检查IP是否被封禁 */ + public boolean isBanned(String ip) { + SysLogLoginIp record = findTodayRecordByIp(ip); + if (record != null && record.getBanUntil() != null) { + if (record.getBanUntil().after(new Date())) { + return true; + } + unblockIp(ip); // 如果已经超过封禁时间,则将该ip的尝试次数与封禁时间设置成0或null + } + return false; + } + + public void unblockIp(String ip) { + SysLogLoginIp byIp = findTodayRecordByIp(ip); + byIp.setTryTimes(0); + byIp.setBanUntil(null); + sysLogLoginIpDao.save(byIp); + } + +} diff --git a/src/main/java/com/mgm/mcrm/logging/services/SysLogLoginService.java b/src/main/java/com/mgm/mcrm/logging/services/SysLogLoginService.java new file mode 100644 index 0000000..fb28646 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/services/SysLogLoginService.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.logging.services; + +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import com.mgm.mcrm.logging.models.SysLogLogin; +import com.mgm.mcrm.logging.repositories.SysLogLoginDao; + +@Service +public class SysLogLoginService { + + @Resource + private SysLogLoginDao sysLogLoginDao; + + public SysLogLogin save(SysLogLogin obj) { + return sysLogLoginDao.save(obj); + } + +} diff --git a/src/main/java/com/mgm/mcrm/logging/services/SysLogOperationService.java b/src/main/java/com/mgm/mcrm/logging/services/SysLogOperationService.java new file mode 100644 index 0000000..74ea020 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/logging/services/SysLogOperationService.java @@ -0,0 +1,18 @@ +package com.mgm.mcrm.logging.services; + +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import com.mgm.mcrm.logging.models.SysLogOperation; +import com.mgm.mcrm.logging.repositories.SysLogOperationDao; + +@Service +public class SysLogOperationService { + + @Resource + private SysLogOperationDao sysLogOperationDao; + + public SysLogOperation save(SysLogOperation obj) { + return sysLogOperationDao.save(obj); + } +} diff --git a/src/main/java/com/mgm/mcrm/notification/config/ApnClientConfig.java b/src/main/java/com/mgm/mcrm/notification/config/ApnClientConfig.java new file mode 100644 index 0000000..e8a4156 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/notification/config/ApnClientConfig.java @@ -0,0 +1,109 @@ +package com.mgm.mcrm.notification.config; + +import com.eatthepath.pushy.apns.ApnsClient; +import com.eatthepath.pushy.apns.ApnsClientBuilder; +import com.eatthepath.pushy.apns.auth.ApnsSigningKey; +import com.eatthepath.pushy.apns.proxy.HttpProxyHandlerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.StringUtils; + +import java.io.InputStream; +import java.net.InetSocketAddress; + +@Configuration +public class ApnClientConfig { + + @Value("${apns.team-id}") + private String teamId; + + @Value("${apns.key-id}") + private String keyId; + + @Value("${apns.key-file}") + private String keyFilePath; + + @Value("${apns.host}") + private String apnHost; + + @Value("${apns.proxy.enabled:false}") + private boolean proxyEnabled; + + @Value("${apns.proxy.host:}") + private String proxyHost; + + @Value("${apns.proxy.port:0}") + private int proxyPort; + + @Value("${apns.proxy.username:}") + private String proxyUsername; + + @Value("${apns.proxy.password:}") + private String proxyPassword; + + @Bean + public ApnsClient apnsClient() throws Exception { + + String tid = teamId != null ? teamId.trim() : ""; + String kid = keyId != null ? keyId.trim() : ""; + + if (!StringUtils.hasText(tid) || !StringUtils.hasText(kid)) { + throw new IllegalStateException("apns.team-id / apns.key-id must be non-empty after trim"); + } + + InputStream privateKeyStream = openApnsKeyStream(keyFilePath); + if (privateKeyStream == null) { + throw new IllegalStateException( + "Cannot load APNs .p8 from classpath (apns.key-file=" + keyFilePath + "). " + + "Put file under src/main/resources and use path like /AuthKey_XXX.p8"); + } + + ApnsClientBuilder builder = new ApnsClientBuilder() + .setSigningKey(ApnsSigningKey.loadFromInputStream(privateKeyStream, tid, kid)) + .setApnsServer(apnHost.trim()); + + if (proxyEnabled) { + String host = proxyHost != null ? proxyHost.trim() : ""; + if (!StringUtils.hasText(host) || proxyPort <= 0) { + throw new IllegalStateException("apns.proxy.host / apns.proxy.port must be configured when apns.proxy.enabled=true"); + } + + InetSocketAddress proxyAddress = new InetSocketAddress(host, proxyPort); + if (StringUtils.hasText(proxyUsername)) { + builder.setProxyHandlerFactory(new HttpProxyHandlerFactory(proxyAddress, proxyUsername.trim(), proxyPassword != null ? proxyPassword : "")); + } else { + builder.setProxyHandlerFactory(new HttpProxyHandlerFactory(proxyAddress)); + } + } + + return builder.build(); + } + + + /** + * Spring Boot / fat jar 下用上下文 ClassLoader 读 resources 比 {@code getClass().getResourceAsStream} + *

+ * 更可靠;兼容 {@code /xxx.p8} 与 {@code xxx.p8} 两种写法。 + */ + + private static InputStream openApnsKeyStream(String configuredPath) { + if (!StringUtils.hasText(configuredPath)) { + return null; + } + + String path = configuredPath.trim(); + String withoutLeadingSlash = path.startsWith("/") ? path.substring(1) : path; + + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + + InputStream in = cl != null ? cl.getResourceAsStream(withoutLeadingSlash) : null; + + if (in != null) { + return in; + } + + return ApnClientConfig.class.getResourceAsStream(path.startsWith("/") ? path : "/" + path); + } +} + diff --git a/src/main/java/com/mgm/mcrm/notification/controllers/EmailTemplateController.java b/src/main/java/com/mgm/mcrm/notification/controllers/EmailTemplateController.java new file mode 100644 index 0000000..669c729 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/notification/controllers/EmailTemplateController.java @@ -0,0 +1,44 @@ +package com.mgm.mcrm.notification.controllers; + +import java.util.List; + +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.notification.dtos.request.GenerateBookingEmailRequest; +import com.mgm.mcrm.notification.services.EmailTemplateService; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import com.mgm.mcrm.notification.models.CfgEmailTemplate; + + +@RestController +@CrossOrigin(origins = "*") +@RequestMapping("/api") +public class EmailTemplateController { + + @Resource + private EmailTemplateService emailTemplateService; + + + @RequestMapping(value = "/web/email_template/send", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> sendEmailTemplates(HttpServletRequest request, @RequestBody CfgEmailTemplate emailTemplate) { + //-- + BaseApiResponse result = emailTemplateService.sendEmailTemplates(emailTemplate,request); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @RequestMapping(value = "/web/email_template/generate", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity>> generateEmailTemplates(HttpServletRequest request, @RequestBody(required=true) GenerateBookingEmailRequest generateRequest) { + BaseApiResponse> result = new BaseApiResponse<>(); + //-- + List listEmailTemplates = emailTemplateService.generateEmailTemplate(generateRequest.getIds()); + result.setData(listEmailTemplates); + result.setSuccess(true); + result.setMessage("Query Success"); + return ResponseEntity.status(HttpStatus.OK).body(result); + } +} diff --git a/src/main/java/com/mgm/mcrm/notification/controllers/NotificationController.java b/src/main/java/com/mgm/mcrm/notification/controllers/NotificationController.java new file mode 100644 index 0000000..ffb6a6a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/notification/controllers/NotificationController.java @@ -0,0 +1,101 @@ +package com.mgm.mcrm.notification.controllers; + +import com.auth0.jwt.JWT; +import com.mgm.mcrm.authorization.dtos.LoginUserInfo; +import com.mgm.mcrm.authorization.models.SysRouterPermission; +import com.mgm.mcrm.authorization.services.SysGroupPermissionService; +import com.mgm.mcrm.common.annotation.logging.OperationLog; +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.notification.dtos.request.ChangeNotificationStatusRequest; +import com.mgm.mcrm.notification.dtos.request.SendNotificationRequest; +import com.mgm.mcrm.notification.dtos.response.ChangeNotificationStatusResponse; +import com.mgm.mcrm.notification.dtos.response.CountNotificationByUserIdResponse; +import com.mgm.mcrm.notification.dtos.response.GetNotificationResponse; +import com.mgm.mcrm.notification.services.NotificationService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; + +@RestController +@RequestMapping("/api/notification") +public class NotificationController { + + @Resource + private NotificationService notificationService; + @Resource + private SysGroupPermissionService sysGroupPermissionService; + + @GetMapping("/get_notification_by_user_id") + public GetNotificationResponse getNotificationByUserId(HttpServletRequest request) { + String token = request.getHeader("Authorization"); + String userId = JWT.decode(token).getClaim("login_id").asString(); + String groupName = JWT.decode(token).getClaim("group_name").asString(); + List userPermissions = new ArrayList(); + GetNotificationResponse response = new GetNotificationResponse(); + boolean viewNotification = false; + + userPermissions = sysGroupPermissionService.getRouterPermissionsByGroupName(groupName); + if(userPermissions.size()>0) { + for(SysRouterPermission per:userPermissions) { + if(StringUtils.equals(per.getId(), "10001_06") ) viewNotification = true; + } + } + if (viewNotification) { + response = notificationService.getNotificationByUserId(userId); + }else{ + response.setSuccess(Boolean.FALSE); + response.setMessage("NO PERMISSION"); + response.setCode("NO_PERMISSION"); + } + return response; + + } + + @GetMapping("/count_notification_by_user_id") + public CountNotificationByUserIdResponse countNotificationByUserId(HttpServletRequest request) { + String token = request.getHeader("Authorization"); + String userId = JWT.decode(token).getClaim("login_id").asString(); + String groupName = JWT.decode(token).getClaim("group_name").asString(); + return notificationService.countNotificationByUserId(userId,groupName); + } + + @PostMapping("/change_status") + public ChangeNotificationStatusResponse changeStatus(@RequestBody ChangeNotificationStatusRequest request) { + Long id = request != null ? request.getId() : null; + return notificationService.changeStatus(id); + } + + @OperationLog(actionName = "Send Notification", eventCode = "send_notification") + @Operation( + summary = "Send Notification", + description = "API to send notification" + ) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "Access Token generated successful"), + @ApiResponse(responseCode = "401", description = "Authorization key not math") + }) + @PostMapping(value="/send_notification",produces = "application/json;charset=UTF-8") + public ResponseEntity> sendNotification( + HttpServletRequest request, + @Parameter(description = "Notification request info", required = true) @Valid @RequestBody SendNotificationRequest requestData) { + LoginUserInfo requestUser = SysCommon.parseUserFromToken(request); + if(requestUser!=null){ + BaseApiResponse responseData = notificationService.sendNotificationByRequest(requestData, requestUser.getLoginId()); + return ResponseEntity.status(HttpStatus.OK).body(responseData); + }else{ + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(null); + } + } +} diff --git a/src/main/java/com/mgm/mcrm/notification/dtos/request/ChangeNotificationStatusRequest.java b/src/main/java/com/mgm/mcrm/notification/dtos/request/ChangeNotificationStatusRequest.java new file mode 100644 index 0000000..975880d --- /dev/null +++ b/src/main/java/com/mgm/mcrm/notification/dtos/request/ChangeNotificationStatusRequest.java @@ -0,0 +1,8 @@ +package com.mgm.mcrm.notification.dtos.request; + +import lombok.Data; + +@Data +public class ChangeNotificationStatusRequest { + private Long id; +} diff --git a/src/main/java/com/mgm/mcrm/notification/dtos/request/GenerateBookingEmailRequest.java b/src/main/java/com/mgm/mcrm/notification/dtos/request/GenerateBookingEmailRequest.java new file mode 100644 index 0000000..1ce7b72 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/notification/dtos/request/GenerateBookingEmailRequest.java @@ -0,0 +1,10 @@ +package com.mgm.mcrm.notification.dtos.request; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +@Data +public class GenerateBookingEmailRequest { + @NotBlank + private String ids; +} diff --git a/src/main/java/com/mgm/mcrm/notification/dtos/request/SendNotificationRequest.java b/src/main/java/com/mgm/mcrm/notification/dtos/request/SendNotificationRequest.java new file mode 100644 index 0000000..0236bc6 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/notification/dtos/request/SendNotificationRequest.java @@ -0,0 +1,30 @@ +package com.mgm.mcrm.notification.dtos.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +@Data +@Schema(description = "Request to send notification by employeeId") +public class SendNotificationRequest { + @Schema(description = "Transaction Id for external tracing, if blank, internal uuid will be generated") + private String transactionId; + + @Schema(description = "Employee Id to receive notification") + @NotBlank(message = "Employee Id must not be empty") + private String employeeId; + + @Schema(description = "Title of message") + @NotBlank(message = "Title of message must not be blank") + private String title; + + @Schema(description = "Content of message") + private String content; + + @Schema(description = "Booking confirmation No if need") + private String confirmationNumber; + + @Schema(description = "Type of booking ") + private String type; + +} diff --git a/src/main/java/com/mgm/mcrm/notification/dtos/response/ChangeNotificationStatusResponse.java b/src/main/java/com/mgm/mcrm/notification/dtos/response/ChangeNotificationStatusResponse.java new file mode 100644 index 0000000..91b3658 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/notification/dtos/response/ChangeNotificationStatusResponse.java @@ -0,0 +1,18 @@ +package com.mgm.mcrm.notification.dtos.response; + +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(description = "Change notification status response") +public class ChangeNotificationStatusResponse extends BaseApiResponse { + + @Schema(description = "Notification id") + private Long id; + + @Schema(description = "Notification status after update") + private Integer status; +} diff --git a/src/main/java/com/mgm/mcrm/notification/dtos/response/CountNotificationByUserIdResponse.java b/src/main/java/com/mgm/mcrm/notification/dtos/response/CountNotificationByUserIdResponse.java new file mode 100644 index 0000000..a77bd35 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/notification/dtos/response/CountNotificationByUserIdResponse.java @@ -0,0 +1,10 @@ +package com.mgm.mcrm.notification.dtos.response; + +import lombok.Data; + +@Data +public class CountNotificationByUserIdResponse { + private Long count; + private Long approvalRoutingCount; + private Long notificationCount; +} diff --git a/src/main/java/com/mgm/mcrm/notification/dtos/response/GetNotificationResponse.java b/src/main/java/com/mgm/mcrm/notification/dtos/response/GetNotificationResponse.java new file mode 100644 index 0000000..0265554 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/notification/dtos/response/GetNotificationResponse.java @@ -0,0 +1,14 @@ +package com.mgm.mcrm.notification.dtos.response; + +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.notification.models.SysLogNotification; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +public class GetNotificationResponse extends BaseApiResponse { + private List notifications; +} diff --git a/src/main/java/com/mgm/mcrm/notification/models/CfgEmailTemplate.java b/src/main/java/com/mgm/mcrm/notification/models/CfgEmailTemplate.java new file mode 100644 index 0000000..6e933b3 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/notification/models/CfgEmailTemplate.java @@ -0,0 +1,182 @@ +package com.mgm.mcrm.notification.models; + +import java.io.Serializable; +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.Transient; + +@Entity +@Table(name="cfg_email_template") +public class CfgEmailTemplate implements Serializable { + //fields in table + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="name") + private String name; + @Column(name="property_id") + private Long propertyId; + @Column(name="type") + private Integer type; + @Column(name="to") + private String to; + @Column(name="cc") + private String cc; + @Column(name="content") + private String content; + @Column(name="field") + private String field; + @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="subject") + private String subject; + @Column(name="sender") + private String sender; + @Transient + private String bookIds; + @Transient + private String showTemp; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Long getPropertyId() { + return propertyId; + } + + public void setPropertyId(Long propertyId) { + this.propertyId = propertyId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getTo() { + return to; + } + + public void setTo(String to) { + this.to = to; + } + + public String getCc() { + return cc; + } + + public void setCc(String cc) { + this.cc = cc; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getField() { + return field; + } + + public void setField(String field) { + this.field = field; + } + + public Date getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + public String getUpdatedBy() { + return updatedBy; + } + + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + public String getBookIds() { + return bookIds; + } + + public void setBookIds(String bookIds) { + this.bookIds = bookIds; + } + + public String getShowTemp() { + return showTemp; + } + + public void setShowTemp(String showTemp) { + this.showTemp = showTemp; + } + + public String getSubject() { + return subject; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public String getSender() { + return sender; + } + + public void setSender(String sender) { + this.sender = sender; + } + + +} diff --git a/src/main/java/com/mgm/mcrm/notification/models/Email.java b/src/main/java/com/mgm/mcrm/notification/models/Email.java new file mode 100644 index 0000000..d95dc90 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/notification/models/Email.java @@ -0,0 +1,110 @@ +package com.mgm.mcrm.notification.models; + +import java.io.Serializable; +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; + +@Entity +@Table(name="email") +public class Email implements Serializable { + //fields in table + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="status") + private Integer status; + @Column(name="book_id") + private Long bookId; + @Column(name="content") + private String content; + @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="error_message") + private String errorMessage; + @Column(name="send_to") + private String sendTo; + @Column(name="send_object") + private String sendObject; + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public Integer getStatus() { + return status; + } + public void setStatus(Integer status) { + this.status = status; + } + public Long getBookId() { + return bookId; + } + public void setBookId(Long bookId) { + this.bookId = bookId; + } + public String getContent() { + return content; + } + public void setContent(String content) { + this.content = content; + } + public Date getCreatedAt() { + return createdAt; + } + public void setCreatedAt(Date createdAt) { + this.createdAt = createdAt; + } + public String getCreatedBy() { + return createdBy; + } + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + public Date getUpdatedAt() { + return updatedAt; + } + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + public String getUpdatedBy() { + return updatedBy; + } + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + public String getErrorMessage() { + return errorMessage; + } + public void setMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + public String getSendTo() { + return sendTo; + } + public void setSendTo(String sendTo) { + this.sendTo = sendTo; + } + public String getSendObject() { + return sendObject; + } + public void setSendObject(String sendObject) { + this.sendObject = sendObject; + } + + + +} diff --git a/src/main/java/com/mgm/mcrm/notification/models/SysLogNotification.java b/src/main/java/com/mgm/mcrm/notification/models/SysLogNotification.java new file mode 100644 index 0000000..be5b96c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/notification/models/SysLogNotification.java @@ -0,0 +1,68 @@ +package com.mgm.mcrm.notification.models; + +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.persistence.*; +import lombok.Data; +import org.hibernate.annotations.Nationalized; + +import java.time.LocalDateTime; + +/** + * 系统通知记录(sys_log_notification)。 + */ +@Data +@Entity +@Table(name = "sys_log_notification") +public class SysLogNotification { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "user_id", length = 64, nullable = false) + private String userId; + + @Column(name = "sender_id", length = 64) + private String senderId; + + @Column(name = "transaction_id") + private String transactionId; + + @Column(name = "device_token") + private String deviceToken; + + @Column(name = "status", nullable = false) + private Integer status; + + @Nationalized + @Column(name = "title", columnDefinition = "NVARCHAR(MAX)") + private String title; + + @Nationalized + @Column(name = "content", columnDefinition = "NVARCHAR(MAX)") + private String content; + + @Column(name = "booking_id", length = 100) + private String bookingId; + + @Column(name = "confirmation_no", length = 100) + private String confirmationNo; + + @Column(name = "booking_type") + private String bookingType; + + @Column(name = "result_message", length = 512) + private String resultMessage; + + @Column(name = "apn_response_id") + private String apnResponseId; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @Column(name = "created_at") + private LocalDateTime createdAt; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @Column(name = "updated_at") + private LocalDateTime updatedAt; +} diff --git a/src/main/java/com/mgm/mcrm/notification/repositories/EmailDao.java b/src/main/java/com/mgm/mcrm/notification/repositories/EmailDao.java new file mode 100644 index 0000000..719d74f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/notification/repositories/EmailDao.java @@ -0,0 +1,11 @@ +package com.mgm.mcrm.notification.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.mgm.mcrm.notification.models.Email; + + + +public interface EmailDao extends JpaRepository { + Email findById(long id); +} diff --git a/src/main/java/com/mgm/mcrm/notification/repositories/EmailTemplateDao.java b/src/main/java/com/mgm/mcrm/notification/repositories/EmailTemplateDao.java new file mode 100644 index 0000000..f1df4e7 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/notification/repositories/EmailTemplateDao.java @@ -0,0 +1,14 @@ +package com.mgm.mcrm.notification.repositories; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import com.mgm.mcrm.notification.models.CfgEmailTemplate; + + +public interface EmailTemplateDao extends JpaRepository { + @Query(value="select * from cfg_email_template where property_id = ?1 and type = ?2",nativeQuery=true) + List getByPropertyIdAndType(Long propertyId,String type); +} diff --git a/src/main/java/com/mgm/mcrm/notification/repositories/SysLogNotificationRepository.java b/src/main/java/com/mgm/mcrm/notification/repositories/SysLogNotificationRepository.java new file mode 100644 index 0000000..c8877fb --- /dev/null +++ b/src/main/java/com/mgm/mcrm/notification/repositories/SysLogNotificationRepository.java @@ -0,0 +1,14 @@ +package com.mgm.mcrm.notification.repositories; + +import com.mgm.mcrm.notification.models.SysLogNotification; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface SysLogNotificationRepository extends JpaRepository { + List findByUserIdAndStatus(String userId, Integer status); + + List findAllByDeviceTokenAndTransactionId(String deviceToken, String transactionId); + + long countByUserIdAndStatus(String userId, Integer status); +} diff --git a/src/main/java/com/mgm/mcrm/notification/services/ApnNotificationService.java b/src/main/java/com/mgm/mcrm/notification/services/ApnNotificationService.java new file mode 100644 index 0000000..63d9043 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/notification/services/ApnNotificationService.java @@ -0,0 +1,140 @@ +package com.mgm.mcrm.notification.services; + +import com.eatthepath.pushy.apns.ApnsClient; +import com.eatthepath.pushy.apns.PushNotificationResponse; +import com.eatthepath.pushy.apns.util.SimpleApnsPayloadBuilder; +import com.eatthepath.pushy.apns.util.SimpleApnsPushNotification; +import com.eatthepath.pushy.apns.util.concurrent.PushNotificationFuture; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.notification.repositories.SysLogNotificationRepository; +import com.mgm.mcrm.notification.models.SysLogNotification; +import jakarta.annotation.Resource; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.List; + +@Service +public class ApnNotificationService { + + @Autowired + private ApnsClient apnsClient; + @Value("${apns.bundle-id}") + private String bundleId; + + @Resource + private SysLogNotificationRepository notificationLogDao; + + private final Logger logger = LoggerFactory.getLogger(ApnNotificationService.class); + + public BaseApiResponse pushApnMessage(String transactionId, String deviceToken, String title, String body, boolean isWaitResponse) { + return pushApnMessage(transactionId, deviceToken, title, body, isWaitResponse, null); + } + + public BaseApiResponse pushApnMessage(String transactionId, String deviceToken, String title, String body, boolean isWaitResponse, String confirmNo) { + BaseApiResponse result = new BaseApiResponse<>(); + if(StringUtils.isBlank(deviceToken)){ + result.setSuccess(false); + result.setMessage("Device Token is empty"); + return result; + }else{ + SimpleApnsPayloadBuilder payloadBuilder = new SimpleApnsPayloadBuilder(); + payloadBuilder + .setAlertTitle(title) + .setAlertBody(body) + .setSound("default") + .setBadgeNumber(1); + if(StringUtils.isNotBlank(confirmNo)){ + payloadBuilder.addCustomProperty("ConfirmNo", confirmNo); + } + String payload = payloadBuilder.build(); + + SimpleApnsPushNotification pushNotification = new SimpleApnsPushNotification( + deviceToken, + bundleId, + payload + ); + result.setData(transactionId); + PushNotificationFuture> + sendFuture = apnsClient.sendNotification(pushNotification); + if(isWaitResponse){ + String resultMessage =""; + boolean isSuccess =false; + String apnResponseId=null; + try { + PushNotificationResponse response = sendFuture.get(); + if(response!=null && response.isAccepted()){ + isSuccess=true; + apnResponseId = response.getApnsId()==null?null:response.getApnsId().toString(); + resultMessage = "APN message pushed success with response Id:"+response.getApnsId(); + }else if(response!=null && !response.isAccepted()){ + resultMessage = "APN message was rejected with reason:"+response.getRejectionReason(); + }else{ + resultMessage = "APN no response"; + } + }catch(Exception err){ + resultMessage = "Push APN message failed with error:"+err.getMessage(); + } + result.setSuccess(isSuccess); + result.setMessage(resultMessage); + if(StringUtils.isNotBlank(transactionId) && StringUtils.isNotBlank(deviceToken)){ + List notificationLogs = notificationLogDao.findAllByDeviceTokenAndTransactionId(deviceToken, transactionId); + if(!notificationLogs.isEmpty()){ + LocalDateTime currentTime = LocalDateTime.now(); + for(SysLogNotification logItem:notificationLogs){ + logItem.setStatus(isSuccess?0:-1); + logItem.setApnResponseId(apnResponseId); + logItem.setUpdatedAt(currentTime); + logItem.setResultMessage(resultMessage); + } + notificationLogDao.saveAll(notificationLogs); + } + } + }else{ + result.setSuccess(true); + result.setMessage("APN message was pushed and process with ASYNC mode, use txnId to trace log"); + // process response in async mode + sendFuture.whenComplete((response, throwable) -> { + String resultMessage =""; + boolean isSuccess =false; + String apnResponseId=null; + if (response != null && response.isAccepted()) { + isSuccess =true; + apnResponseId = response.getApnsId()==null?null:response.getApnsId().toString(); + resultMessage = "APN message pushed success with response Id:"+response.getApnsId(); + } else if (response != null && !response.isAccepted()) { + resultMessage = "APN message was rejected with reason:"+response.getRejectionReason(); + } else { + if(throwable!=null){ + resultMessage = "Push APN message failed with error:"+throwable.getMessage(); + }else{ + resultMessage = "APN no response"; + } + } + if(!isSuccess) + logger.error(resultMessage); + //-- update notification log + if(StringUtils.isNotBlank(transactionId) && StringUtils.isNotBlank(deviceToken)){ + List notificationLogs = notificationLogDao.findAllByDeviceTokenAndTransactionId(deviceToken, transactionId); + if(!notificationLogs.isEmpty()){ + LocalDateTime currentTime = LocalDateTime.now(); + for(SysLogNotification logItem:notificationLogs){ + logItem.setStatus(isSuccess?0:-1); + logItem.setApnResponseId(apnResponseId); + logItem.setUpdatedAt(currentTime); + logItem.setResultMessage(resultMessage); + } + notificationLogDao.saveAll(notificationLogs); + } + } + }); + } + } + return result; + } +} diff --git a/src/main/java/com/mgm/mcrm/notification/services/EmailTemplateService.java b/src/main/java/com/mgm/mcrm/notification/services/EmailTemplateService.java new file mode 100644 index 0000000..2d9fd6f --- /dev/null +++ b/src/main/java/com/mgm/mcrm/notification/services/EmailTemplateService.java @@ -0,0 +1,342 @@ +package com.mgm.mcrm.notification.services; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; + +import com.mgm.mcrm.booking.models.BookingsView; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +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; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; + +import com.mgm.mcrm.booking.repositories.BookingDao; +import com.mgm.mcrm.booking.repositories.BookingViewDao; +import com.mgm.mcrm.notification.repositories.EmailDao; +import com.mgm.mcrm.notification.repositories.EmailTemplateDao; +import com.mgm.mcrm.basesetting.room.repositories.OtherRoomStatusDao; +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.notification.models.CfgEmailTemplate; +import com.mgm.mcrm.notification.models.Email; +import com.mgm.mcrm.common.dtos.mgm_api.UserInfoApiRecord; +import com.mgm.mcrm.authorization.services.MgmUserService; +import com.mgm.mcrm.logging.services.SysLogBookingService; +import com.mgm.mcrm.common.utils.DateTimeUtil; +import com.mgm.mcrm.common.utils.SendEmail; + +@Service +public class EmailTemplateService { + + @Resource + private EmailTemplateDao emailTemplateDao; + @Resource + private EmailDao emailDao; + @Resource + private BookingViewDao bookViewDao; + @Resource + private MgmUserService mgmUserService; + @Resource + private SysLogBookingService sysLogBookingService; + @Resource + private BookingDao bookingDao; + @Resource + private OtherRoomStatusDao roomStatusDao; + + private static String emailTemp = + "

{{title}}
"+ + "

" + + "
{{content}}
"+ + "

" + + "{{table}}"; + + private static String tableTemp = + "\r\n" + + " \r\n" + + " \r\n" + + " {{thead}}"+ + " \r\n" + + " \r\n" + + " \r\n" + + " {{tbody}}"+ + " \r\n" + + "
"; + + public BaseApiResponse sendEmailTemplates(CfgEmailTemplate emailTemplate, HttpServletRequest request) { + BaseApiResponse processResult= new BaseApiResponse<>(); + String idString = Strings.CS.replace(emailTemplate.getBookIds(), ";", ","); + List getEmailList = generateEmailTemplate(idString); + boolean res = false; + if(!getEmailList.isEmpty()) { + res = SendEmail.sendOtherBookingEmail(getEmailList.getFirst()); + String[] ids = emailTemplate.getBookIds().split(";"); + ArrayList idList = new ArrayList<>(); + List emailList = new ArrayList<>(); + ArrayList resultBookings = new ArrayList<>(); + for(String id : ids) { + Email email = new Email(); + email.setBookId(Long.valueOf(id)); + email.setCreatedAt(new Date()); + email.setCreatedBy(emailTemplate.getCreatedBy()); + email.setContent(emailTemplate.getContent()); + email.setStatus(res?1:0); + email.setSendTo(emailTemplate.getTo()); + emailList.add(email); + idList.add(Long.valueOf(id)); + Bookings emailBook = bookingDao.findById(Long.parseLong(id)).orElse(null); + if(emailBook.getOtherFollowUpStatusId()==5) { + emailBook.setOtherFollowUpStatusId(4L); + emailBook.setOtherRoomStatusId(roomStatusDao.getCancelId()); + bookingDao.save(emailBook); + } + } + resultBookings = bookingDao.findByIdIn(idList); + sysLogBookingService.saveLogBooking(resultBookings, request, "", "", "Send Email",""); + emailDao.saveAll(emailList); + } + + if(res) { + processResult.setSuccess(true); + processResult.setMessage("Send Email Succeed."); + }else { + processResult.setSuccess(false); + processResult.setCode("ERR_FAILED"); + processResult.setMessage("Send Email Failed."); + } + + processResult.setData(emailTemplate); + return processResult; + } + + public List generateEmailTemplate(String bookingIds) { + String ids = (bookingIds==null?"":bookingIds); + List bookList = bookViewDao.findBookingByIds(ids.split(",")); + HashMap bookMap = new HashMap(); + HashMap typeMap = new HashMap(); + if(!bookList.isEmpty()) { + for(BookingsView book : bookList) { + Bookings getBook = bookingDao.findById(book.getId()).orElse(null); + if(book.getRequestedCoDate()!=null) { + book.setBookType("1"); + }else if(getBook.getOtherFollowUpStatusId()==5){ + book.setBookType("2"); + }else { + book.setBookType("0"); + } + if(bookMap.get(book.getPropertyId())!=null) { + typeMap = (HashMap) bookMap.get(book.getPropertyId()); + if(typeMap.get(book.getBookType())!=null) { + List typeList = typeMap.get(book.getBookType()); + typeList.add(book); + typeMap.put(book.getBookType(), typeList); + bookMap.put(book.getPropertyId(), typeMap); + }else { + List typeList = new ArrayList(); + typeList.add(book); + typeMap.put(book.getBookType(), typeList); + bookMap.put(book.getPropertyId(), typeMap); + } + }else { + typeMap = new HashMap(); + List typeList = new ArrayList(); + typeList.add(book); + typeMap.put(book.getBookType(), typeList); + bookMap.put(book.getPropertyId(), typeMap); + } + } + } + + return getTemplateContent(bookMap); + } + + private List getTemplateContent(HashMap bookMap) { + ArrayList emailList = new ArrayList(); + for (Long key : bookMap.keySet()) { + HashMap getTypeMap = bookMap.get(key); + for (String skey : getTypeMap.keySet()) { + List typeList = getTypeMap.get(skey); + List templates = emailTemplateDao.getByPropertyIdAndType(key, skey); + if(templates.size()==0) continue; + CfgEmailTemplate template = templates.getFirst(); + String temp = emailTemp; + String propertyName = typeList.getFirst().getPropertyEmailName(); + if(Strings.CI.contains(propertyName, "mandarin")) propertyName="MO"; + String title = "Dear "+propertyName+" Team,"; + String content = template.getContent(); + String table = ""; + List bookIdList = new ArrayList(); + if(!StringUtils.isEmpty(template.getField())) { + //New Booking Request + table = tableTemp; + String[] fieledList = template.getField().split(";"); + String thread = "No"; + for( String field : fieledList) { + thread+=""+field+""; + } + String tbody = ""; + int index = 1; + for(BookingsView bo:typeList) { + tbody+=""+index+""; + index++; + bookIdList.add(String.valueOf(bo.getId())); + for( String field : fieledList) { + + String getFiled = getNewFiled(field, bo); + tbody+=""+getFiled+""; + } + tbody+=""; + } + table = table.replace("{{thead}}", thread); + table = table.replace("{{tbody}}", tbody); + }else { + content=""; + for(BookingsView bo:typeList) { + bookIdList.add(String.valueOf(bo.getId())); + content+=getExtendFiled(bo,template.getContent())+"
"; + } + } + temp = temp.replace("{{title}}", title); + temp = temp.replace("{{content}}", content); + temp = temp.replace("{{table}}", table); + template.setShowTemp(temp); + template.setBookIds(String.join(";", bookIdList)); + emailList.add(template); + } + } + return emailList; + } + + private String getNewFiled(String name, BookingsView book) { + String field = ""; + String bookNameStr = Strings.CS.replace(book.getMemberLastName(), ", ", ";"); + String[] bookNameArr = StringUtils.split(bookNameStr, ";"); + BaseApiResponse userInfoRes = mgmUserService.findUserInfoByUserId(book.getCreatedBy()); + UserInfoApiRecord userInfo = userInfoRes.getData(); + switch (name) { + case "Title": + field = book.getMemberTitle()!=null?book.getMemberTitle():""; + break; + case "Last Name": + if(bookNameArr!=null&&bookNameArr.length>1) { + field = bookNameArr[0]; + } else { + field = book.getMemberLastName()!=null?book.getMemberLastName():""; + } + break; + case "First Name": + if(bookNameArr!=null&&bookNameArr.length>1) { + field = bookNameArr[1]; + } else { + field = book.getMemberLastName()!=null?book.getMemberLastName():""; + } + break; + case "Member ID": + field = book.getPlayerId()!=null?book.getPlayerId():""; + break; + case "Tier": + field = book.getTier()!=null?book.getTier():""; + break; + case "C/I": + field = DateTimeUtil.getDateByFormat(book.getCheckinDate(), "yyyy-MM-dd"); + break; + case "C/O": + field = DateTimeUtil.getDateByFormat(book.getCheckoutDate(), "yyyy-MM-dd"); + break; + case "Property": + field = book.getPropertyEmailName()!=null?book.getPropertyEmailName():""; + break; + case "Room Type": +// field = getRoomType(book.getRoom(),book.getPropertyName()); + field = book.getRoomEmailName()!=null?book.getRoomEmailName():""; + break; + case "Booker & Contact": + String booker = ""; + boolean isMo = Strings.CI.contains(book.getPropertyName(), "mandarin"); + if(Strings.CS.equals("CCREL", book.getMarketCode())) { + booker = "CR"; + }else { + booker = "BD"; + } + String phone = ""; + if(Strings.CS.equals(booker, "CR")){ + phone = "-88022488"; + }else if(Strings.CS.equals(booker, "BD")) { + if(isMo) { + if(userInfo!=null&&!StringUtils.isEmpty(userInfo.getPhone())) { + phone = "-"+userInfo.getPhone(); + } + }else { + phone = "-88028802"; + } + } + + if(isMo) { + if(userInfo!=null&&!StringUtils.isEmpty(userInfo.getUserName())) { + booker = userInfo.getUserName(); + } + phone = Strings.CS.replace(phone, "-", " "); + } + + field = booker + phone; + break; + case "Sharer": + field = getSharer(book.getSharer()); + break; + case "Remark": + String proName = book.getPropertyName(); + if(!StringUtils.isEmpty(proName)) { + proName = Strings.CS.replace(proName, "'", ""); + if(Strings.CI.contains(proName, "larc")) { + field = "NEW "; + } + } + + field += book.getRemark()!=null?book.getRemark():""; + break; + case "Conf#": + field = book.getConfirmationNo()!=null?book.getConfirmationNo():""; + break; + default: + break; + } + return field; + } + + private String getExtendFiled(BookingsView book,String content) { + content = content.replace("{{Conf#}}", book.getConfirmationNo()!=null?book.getConfirmationNo():""); + content = content.replace("{{Title}}", book.getMemberTitle()!=null?book.getMemberTitle():""); + content = content.replace("{{Member Name}}", book.getMemberLastName()!=null?book.getMemberLastName():""); + if(book.getRequestedCoDate()!=null) { + content = content.replace("{{C/O}}", DateTimeUtil.getDateByFormat(book.getRequestedCoDate(), "yyyy-MM-dd")); + } + return content; + } + + private String getSharer(String sharers) { + String getSharerName = ""; + if(sharers!=null&&!Strings.CS.equals("[]", sharers)) { + JSONArray sharerArr = JSONArray.parseArray(sharers); + ArrayList sharerId = new ArrayList(); + ArrayList sharerName = new ArrayList(); + for(Object sharer : sharerArr) { + JSONObject sharerObj = (JSONObject) sharer; + if(sharerObj.containsKey("playerId")) { + sharerId.add(sharerObj.get("playerId")); + } + if(sharerObj.containsKey("name")) { + sharerName.add(sharerObj.get("name")); + } + } + getSharerName = String.join(";", sharerName); + } + return getSharerName; + } + +} + diff --git a/src/main/java/com/mgm/mcrm/notification/services/NotificationService.java b/src/main/java/com/mgm/mcrm/notification/services/NotificationService.java new file mode 100644 index 0000000..e66b3be --- /dev/null +++ b/src/main/java/com/mgm/mcrm/notification/services/NotificationService.java @@ -0,0 +1,201 @@ +package com.mgm.mcrm.notification.services; + +import com.mgm.mcrm.authorization.models.SysRouterPermission; +import com.mgm.mcrm.authorization.services.SysGroupPermissionService; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.common.utils.LogUtil; +import com.mgm.mcrm.logging.models.SysLogDeviceToken; +import com.mgm.mcrm.logging.repositories.SysLogDeviceTokenDao; +import com.mgm.mcrm.notification.dtos.request.SendNotificationRequest; +import com.mgm.mcrm.notification.dtos.response.ChangeNotificationStatusResponse; +import com.mgm.mcrm.notification.dtos.response.CountNotificationByUserIdResponse; +import com.mgm.mcrm.notification.dtos.response.GetNotificationResponse; +import com.mgm.mcrm.notification.models.SysLogNotification; +import com.mgm.mcrm.notification.repositories.SysLogNotificationRepository; +import jakarta.annotation.Resource; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +@Service +public class NotificationService { + @Resource + private SysLogNotificationRepository sysLogNotificationRepository; + @Resource + private ApnNotificationService apnNotificationService; + @Resource + private SysLogDeviceTokenDao sysLogDeviceTokenDao; +// @Resource +// private ApprovalRoutingDao approvalRoutingDao; + @Resource + private SysGroupPermissionService sysGroupPermissionService; + + + public GetNotificationResponse getNotificationByUserId(String userId){ + GetNotificationResponse response = new GetNotificationResponse(); + response.setNotifications(sysLogNotificationRepository.findByUserIdAndStatus(userId, 0)); + response.setSuccess(!response.getNotifications().isEmpty()); + return response; + } + + public CountNotificationByUserIdResponse countNotificationByUserId (String userId,String groupName){ + CountNotificationByUserIdResponse response = new CountNotificationByUserIdResponse(); + List userPermissions = new ArrayList(); + boolean viewNotification = false; + boolean viewApprovalRouting = false; + Long count = 0L; + + userPermissions = sysGroupPermissionService.getRouterPermissionsByGroupName(groupName); + if(userPermissions.size()>0) { + for(SysRouterPermission per:userPermissions) { + if(StringUtils.equals(per.getId(), "10001_05") ) viewApprovalRouting = true; + if(StringUtils.equals(per.getId(), "10001_06") ) viewNotification = true; + } + } + +// if (viewApprovalRouting) { +// response.setApprovalRoutingCount( approvalRoutingDao.countApprovalList(userId)); +// count+=approvalRoutingDao.countApprovalList(userId); +// } + if (viewNotification) { + response.setNotificationCount(sysLogNotificationRepository.countByUserIdAndStatus(userId, 0)); + count+=sysLogNotificationRepository.countByUserIdAndStatus(userId, 0); + } + response.setCount(count); + return response; + } + + public ChangeNotificationStatusResponse changeStatus(Long id) { + ChangeNotificationStatusResponse response = new ChangeNotificationStatusResponse(); + if (id == null) { + response.setSuccess(false); + response.setCode("400"); + response.setMessage("id is required"); + return response; + } + Optional optional = sysLogNotificationRepository.findById(id); + if (optional.isEmpty()) { + response.setSuccess(false); + response.setCode("404"); + response.setMessage("Notification not found"); + return response; + } + LogUtil.info(NotificationService.class,"Notification status changed,Id = "+id); + SysLogNotification notification = optional.get(); + notification.setStatus(1); + notification.setUpdatedAt(LocalDateTime.now()); + SysLogNotification saved = sysLogNotificationRepository.save(notification); + response.setSuccess(true); + response.setCode("200"); + response.setId(saved.getId()); + response.setStatus(saved.getStatus()); + return response; + } + + + public BaseApiResponse sendNotificationByRequest(SendNotificationRequest requestData, String senderId) { + BaseApiResponse result = new BaseApiResponse<>(); + String[] userIds = requestData.getEmployeeId().split("[;,]"); + String transactionId = requestData.getTransactionId(); + if(StringUtils.isBlank(transactionId)){ + transactionId = UUID.randomUUID().toString(); + } + result.setData(transactionId); + if(userIds.length>0){ + int successCount =0; + for(String userId:userIds){ + if(StringUtils.isNotBlank(userId)){ + userId = userId.trim(); + SysLogDeviceToken deviceToken = sysLogDeviceTokenDao.findByUserId(userId); + String deviceTokenValue =null; + if(deviceToken!=null){ + deviceTokenValue = deviceToken.getDeviceToken(); + } + + Integer useLanguage = deviceToken == null ? null : deviceToken.getUseLanguageType(); + String notificationTitle = resolveNotificationText(requestData.getTitle(), useLanguage); + String notificationContent = resolveNotificationText(requestData.getContent(), useLanguage); + + //这里需要加上判断,判断deviceToken中的UseLanguage是什么语言 0:英文 1:中文 根据不同的Language来推送不同语言的通知 + + SysLogNotification notificationLog = createNotificationLogByRequest(requestData,transactionId,senderId,userId,deviceTokenValue,notificationTitle,notificationContent); + if(StringUtils.isBlank(deviceTokenValue)){ + notificationLog.setStatus(-1); + notificationLog.setResultMessage("No APN token is setup for user:"+userId); + notificationLog.setUpdatedAt(LocalDateTime.now()); + } + sysLogNotificationRepository.save(notificationLog); + //-- Process APN sending + BaseApiResponse sendResult = apnNotificationService.pushApnMessage( + transactionId, + deviceTokenValue, + notificationTitle, + notificationContent, + true, + requestData.getConfirmationNumber()); + if(sendResult.isSuccess()){ + successCount++; + } + } + } + if(successCount>0){ + result.setSuccess(true); + }else{ + result.setSuccess(false); + result.setMessage("No message was success processed"); + } + }else{ + result.setSuccess(false); + result.setMessage("employeeId list is empty"); + } + return result; + } + + private SysLogNotification createNotificationLogByRequest(SendNotificationRequest requestData,String transactionId, String senderId, String userId, String deviceToken, String title, String content){ + SysLogNotification notificationLog = new SysLogNotification(); + notificationLog.setUserId(userId); + notificationLog.setDeviceToken(deviceToken); + notificationLog.setSenderId(senderId); + notificationLog.setStatus(0); + notificationLog.setConfirmationNo(requestData.getConfirmationNumber()); + notificationLog.setBookingType(requestData.getType()); + notificationLog.setTitle(title); + notificationLog.setContent(content); + notificationLog.setTransactionId(transactionId); + notificationLog.setCreatedAt(LocalDateTime.now()); + return notificationLog; + } + + private static String resolveNotificationText(String text, Integer useLanguage) { + if (StringUtils.isBlank(text)) { + return text; + } + String preferredTag = Integer.valueOf(1).equals(useLanguage) ? "CN" : "EN"; + String fallbackTag = Integer.valueOf(1).equals(useLanguage) ? "EN" : "CN"; + String preferredText = extractNotificationText(text, preferredTag); + if (StringUtils.isNotBlank(preferredText)) { + return preferredText; + } + String fallbackText = extractNotificationText(text, fallbackTag); + return StringUtils.isNotBlank(fallbackText) ? fallbackText : text; + } + + private static String extractNotificationText(String text, String tag) { + String marker = "#" + tag + "#"; + int start = text.indexOf(marker); + if (start < 0) { + return null; + } + start += marker.length(); + int end = text.indexOf(marker, start); + if (end < 0) { + return null; + } + return text.substring(start, end).trim(); + } +} diff --git a/src/main/java/com/mgm/mcrm/player/controllers/PlayerController.java b/src/main/java/com/mgm/mcrm/player/controllers/PlayerController.java new file mode 100644 index 0000000..cc82886 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/controllers/PlayerController.java @@ -0,0 +1,200 @@ +package com.mgm.mcrm.player.controllers; + +import java.util.List; +import java.util.Map; + +import com.auth0.jwt.JWT; +import com.mgm.mcrm.authorization.dtos.LoginUserInfo; +import com.mgm.mcrm.booking.dtos.search.CheckSecondTPDRequest; +import com.mgm.mcrm.booking.dtos.search.CheckTPDRequest; +import com.mgm.mcrm.booking.dtos.search.DateRange; +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.common.dtos.mgm_api.PlayerTPDApiResult; +import com.mgm.mcrm.player.dtos.request.WebCheckPlayerTPDRequest; +import com.mgm.mcrm.player.dtos.request.WebPlayerLookupRequest; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import com.mgm.mcrm.common.dtos.mgm_api.PlayerProfileEntry; +import com.mgm.mcrm.player.services.PlayerService; +import com.mgm.mcrm.appsetting.services.SysSettingService; + +@RestController +@CrossOrigin(origins = "*") +@RequestMapping("/api") +public class PlayerController { + + @Resource + private PlayerService playerService; + + @Resource + private SysSettingService sysSettingService; + + @RequestMapping(value = "/app/mgm/player_lookup", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public BaseApiResponse getPlayerProfileByPlayerId(HttpServletRequest request, @RequestBody(required=false) Map params) { + String playerId = params.get("playerId"); +// String userId = params.get("userId"); + String token = request.getHeader("Authorization"); + String userId = JWT.decode(token).getClaim("login_id").asString(); + + if(StringUtils.isNotEmpty(userId)) { + userId = Strings.CS.replace(userId, "@mgm.mo", ""); + } + + BaseApiResponse result = playerService.findPlayerProfileByPlayerIdAndUserId(playerId, userId); + //result = AjaxResultMockup.mockupResult("\\mockup\\app\\playerProfile.json"); + if(result.isSuccess()) { + result.setSuccess(true); + result.setData(result.getData()); + }else { + result.setSuccess(false); + result.setMessage(result.getMessage()); + } + return result; + } + + @RequestMapping(value = "/app/mgm/check_tpd_by_playerId_room_dates", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> checkTPDByPlayerIdAndRoomCatAndDates(HttpServletRequest request, + @RequestBody(required=true) CheckTPDRequest params) { + String playerId = params.getPlayerId(); + String roomCat = params.getRoomCat(); + String bookingType = params.getBookingType(); + String property = params.getProperty(); + List dates = params.getDates(); + LoginUserInfo loginUser = SysCommon.parseUserFromToken(request); + BaseApiResponse result = new BaseApiResponse<>(); + BaseApiResponse checkTPDResult = new BaseApiResponse<>(); + String userId = loginUser.getLoginId(); + BaseApiResponse findPlayerResult = playerService.findPlayerProfileByPlayerIdAndUserId(playerId, userId); + if(findPlayerResult.isSuccess()) { + PlayerProfileEntry profile = findPlayerResult.getData(); + Integer code = profile.getCodedFlag(); + if(code==1) { + checkTPDResult = playerService.checkTPDByPlayerIdAndRoomAndDates(playerId,roomCat,dates,bookingType,property); + result.setMessage(checkTPDResult.getMessage()); + }else { + result.setMessage("No permission to view"); + } + }else { + result.setMessage(findPlayerResult.getMessage()); + } + + //result = AjaxResultMockup.mockupResult("\\mockup\\app\\playerProfile.json"); + if(checkTPDResult.isSuccess()) { + result.setSuccess(true); + result.setData(checkTPDResult.getData()); + }else { + result.setSuccess(false); + } + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @RequestMapping(value = "/app/mgm/check_second_tpd_by_playerId_room_dates", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> checkSecondRoomTPDByPlayerIdAndRoomCatAndDates(HttpServletRequest request, + @RequestBody(required=true) CheckSecondTPDRequest params) { + String playerId = params.getPlayerId(); + String roomCat = params.getRoomCat(); + String bookingType = params.getBookingType(); + String property = params.getProperty(); + List dates = params.getDates(); + List dateRange = params.getDateRange(); + LoginUserInfo loginUser = SysCommon.parseUserFromToken(request); + String userId = loginUser.getLoginId(); + + boolean isMock = sysSettingService.isAPPMock(); + BaseApiResponse result = new BaseApiResponse<>(); + BaseApiResponse checkTPDResult = new BaseApiResponse<>(); + BaseApiResponse findPlayerResult = playerService.findPlayerProfileByPlayerIdAndUserId(playerId, userId); + if(findPlayerResult.isSuccess()) { + PlayerProfileEntry profile = findPlayerResult.getData(); + Integer code = profile.getCodedFlag(); + if(code==1) { + if(isMock) { + checkTPDResult = playerService.checkTPDByPlayerIdAndRoomAndDates(playerId,roomCat,dates,bookingType,property); + }else { + checkTPDResult = playerService.checkSecondTPDByPlayerIdAndRoomAndDates(playerId, roomCat, dateRange, dates, bookingType,property); + } + result.setMessage(checkTPDResult.getMessage()); + }else { + result.setMessage("No permission to view"); + } + }else { + result.setMessage(findPlayerResult.getMessage()); + } + + if(checkTPDResult.isSuccess()) { + result.setSuccess(true); + result.setData(checkTPDResult.getData()); + }else { + result.setSuccess(false); + } + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @RequestMapping(value = "/web/player/lookup", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> lookupPlayer(HttpServletRequest request, HttpServletResponse response, + @RequestBody WebPlayerLookupRequest params) throws Exception { + BaseApiResponse processResult = new BaseApiResponse<>(); + String playerId = params.getPlayerId(); + String userId = params.getUserId(); + + if (StringUtils.isEmpty(playerId)) { + response.sendError(422, "Miss parameter player_id"); + return null; + } + if(StringUtils.isNotEmpty(userId)) { + userId = userId.replace("@mgm.mo", ""); + } + BaseApiResponse serviceResult = playerService.findWebPlayerProfileByPlayerId(playerId); + if(serviceResult.isSuccess()) { + processResult.setSuccess(true); + processResult.setData(serviceResult.getData()); + }else { + processResult.setSuccess(false); + processResult.setMessage(serviceResult.getMessage()); + } + //-- + return ResponseEntity.status(HttpStatus.OK).body(processResult); + } + + @RequestMapping(value = "/web/mgm/check_tpd_by_playerId_room_dates", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> checkFirstRoomCriteria(HttpServletRequest request, + @RequestBody WebCheckPlayerTPDRequest params) { + String playerId = params.getPlayerId(); + String roomCat = params.getRoomCat(); + String bookingType = params.getBookingType(); + String property = params.getProperty(); + List dates = params.getDates(); + + BaseApiResponse result = playerService.checkTPDByPlayerIdAndRoomAndDates(playerId, roomCat,dates, bookingType, property); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @RequestMapping(value = "/web/mgm/check_second_tpd_by_playerId_room_dates", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> checkSecondRoomCriteria(HttpServletRequest request, + @RequestBody WebCheckPlayerTPDRequest params) { + String playerId = params.getPlayerId(); + String roomCat = params.getRoomCat(); + String bookingType = params.getBookingType(); + String property = params.getProperty(); + List dates = params.getDates(); + List dateRange = params.getDateRange(); + + boolean isMock = sysSettingService.isAPPMock(); + BaseApiResponse result = new BaseApiResponse<>(); + if(isMock) { + result = playerService.checkTPDByPlayerIdAndRoomAndDates(playerId, roomCat, dates, bookingType, property); + }else { + result = playerService.checkSecondTPDByPlayerIdAndRoomAndDates(playerId, roomCat, dateRange, dates, bookingType, property); + } + return ResponseEntity.status(HttpStatus.OK).body(result); + } +} diff --git a/src/main/java/com/mgm/mcrm/player/controllers/TodoController.java b/src/main/java/com/mgm/mcrm/player/controllers/TodoController.java new file mode 100644 index 0000000..b909290 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/controllers/TodoController.java @@ -0,0 +1,270 @@ +package com.mgm.mcrm.player.controllers; + +import java.sql.Date; +import java.util.ArrayList; +import java.util.List; + +import com.mgm.mcrm.authorization.dtos.LoginUserInfo; +import com.mgm.mcrm.authorization.models.SysRouterPermission; +import com.mgm.mcrm.authorization.services.SysGroupPermissionService; +import com.mgm.mcrm.booking.dtos.BookingDto; +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.common.dtos.mgm_api.TodoDashboardResult; +import com.mgm.mcrm.common.dtos.mgm_api.TodoDateListResult; +import com.mgm.mcrm.common.dtos.mgm_api.TodoDetailResult; +import com.mgm.mcrm.logging.models.SysLogETA; +import com.mgm.mcrm.player.dtos.request.*; +import com.mgm.mcrm.player.dtos.response.GetDashboardResponse; +import com.mgm.mcrm.player.dtos.response.GetTodoDetailResponse; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import com.mgm.mcrm.common.dtos.mgm_api.PlayerProfileEntry; +import com.mgm.mcrm.player.services.PlayerService; +import com.mgm.mcrm.player.services.TodoService; +import com.mgm.mcrm.logging.services.SysLogETAService; + +@RestController +@CrossOrigin(origins = "*") +@RequestMapping("/api") +public class TodoController { + + @Resource + private TodoService todoService; + + @Resource + private PlayerService playerService; + + @Resource + private SysLogETAService sysLogETAService; + + @Resource + private SysGroupPermissionService sysGroupPermissionService; + + @RequestMapping(value = "/app/todo/get_dashboard_data", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> getTodoDashboard(HttpServletRequest request, @RequestBody GetDashboardRequest getDashboardRequest) throws Exception { + + LoginUserInfo loginUser = SysCommon.parseUserFromToken(request); + String userId = loginUser.getLoginId(); + String groupName = loginUser.getGroupName(); + + BaseApiResponse result = new BaseApiResponse<>(); + boolean viewTodoDashboard = sysGroupPermissionService.checkGroupPermission(groupName, "10001_04"); + viewTodoDashboard = true; + if(viewTodoDashboard) { + GetDashboardResponse getDashboardResponse = todoService.getTodoDashboard(userId); + if(getDashboardResponse.isSuccess()) { + result.setSuccess(true); + result.setData(getDashboardResponse.getReturnData()); + }else { + result.setSuccess(false); + result.setMessage(getDashboardResponse.getErrorMessage()); + result.setCode(getDashboardResponse.getErrorCode()); + } + }else { + result.setSuccess(false); + result.setCode("NO_PERMISSION"); + } + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @RequestMapping(value = "/app/todo/get_todolist_details", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> getTodoDetail(HttpServletRequest request, @RequestBody GetTodoDetailRequest getTodoDetailRequest) throws Exception { + String playerId = getTodoDetailRequest.getPlayerId(); + String todoSegment = getTodoDetailRequest.getTodosegment(); + String todoCategory = getTodoDetailRequest.getTodoCategory(); + String date = getTodoDetailRequest.getDate(); + date = date.split("T")[0]; + + BaseApiResponse result = new BaseApiResponse<>(); + + GetTodoDetailResponse getTodoDetailResponse = todoService.getTodoDetail(playerId,todoCategory,todoSegment,date); + if(getTodoDetailResponse.isSuccess()) { + result.setSuccess(true); + result.setData(getTodoDetailResponse.getReturnData()); + }else { + result.setSuccess(false); + result.setCode(getTodoDetailResponse.getErrorCode()); + } + + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @RequestMapping(value = "/app/todo/get_todolist", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> getTodoList(HttpServletRequest request, @RequestBody GetTodoListRequest params) throws Exception { + + LoginUserInfo loginUser = SysCommon.parseUserFromToken(request); + String type = params.getTodoSegment(); + String category = params.getTodoCategory(); + Date startDate = Date.valueOf(params.getStartDate()); + Date endDate = Date.valueOf(params.getEndDate()); + + String userId = loginUser.getLoginId(); + String groupName = loginUser.getGroupName(); + boolean viewTodoList = sysGroupPermissionService.checkGroupPermission(groupName, "10001_03"); + + BaseApiResponse result = new BaseApiResponse<>(); + viewTodoList = true; + if(viewTodoList) { + BaseApiResponse serviceResult = todoService.getTodoList(userId,category,type,startDate,endDate); + if(serviceResult.isSuccess()) { + result.setSuccess(true); + result.setData(serviceResult.getData()); + }else { + result.setSuccess(false); + result.setCode(serviceResult.getCode()); + } + }else { + result.setSuccess(false); + result.setCode("NO_PERMISSION"); + } + + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @RequestMapping(value = "/app/todo/change_date", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> changeDate(HttpServletRequest request, @RequestBody TodoChangeDateRequest bookingParams) throws Exception { + BaseApiResponse result = new BaseApiResponse<>(); + result.setRequestData(bookingParams); + LoginUserInfo loginUser = SysCommon.parseUserFromToken(request); + String userId = loginUser.getLoginId(); + String groupName = loginUser.getGroupName(); + //--get group permissions + boolean cancelBooking = true; + List userPermissions = new ArrayList(); + userPermissions = sysGroupPermissionService.getRouterPermissionsByGroupName(groupName); + if(userPermissions!=null && !userPermissions.isEmpty()) { + for(SysRouterPermission per:userPermissions) { + if(Strings.CS.equals(per.getId(), "10001_02") ) cancelBooking = true; + } + } + String playerId = bookingParams.getPlayerId()!=null? bookingParams.getPlayerId():null; + BaseApiResponse findPlayerProfileResult = playerService.findPlayerProfileByPlayerIdAndUserId(playerId, userId); + if(findPlayerProfileResult.isSuccess()) { + PlayerProfileEntry profile = findPlayerProfileResult.getData(); + Integer code = profile.getCodedFlag(); + if(code==1 && cancelBooking) { + BaseApiResponse changeDateResult = todoService.changeBookingDate(bookingParams,request); + if(changeDateResult.isSuccess()) { + result.setSuccess(true); + result.setMessage(!StringUtils.isEmpty(changeDateResult.getMessage())?changeDateResult.getMessage():"Edit Success"); + result.setData(changeDateResult.getData()); + result.setRequestData(changeDateResult.getData()); + }else { + result.setSuccess(false); + result.setMessage(changeDateResult.getMessage()); + result.setCode(changeDateResult.getCode()); + } + }else { + result.setSuccess(false); + result.setCode("NO_PERMISSION"); + result.setMessage("No permission to cancel"); + } + }else { + result.setSuccess(false); + result.setCode("CALL_API_ERROR"); + result.setMessage(findPlayerProfileResult.getMessage()); + } + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @RequestMapping(value = "/app/todo/submit_ETA", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> submitETA(HttpServletRequest request, + @RequestBody TodoSubmitETARequest params) throws Exception { + LoginUserInfo loginUser = SysCommon.parseUserFromToken(request); + String userId = loginUser.getLoginId(); + String playerId = params.getPlayerId(); + String etaTime = params.getEtaTime(); + Long id = params.getId(); + List recordInfos = params.getRecordInfo(); + BaseApiResponse result = new BaseApiResponse<>(); + + if(StringUtils.isNotEmpty(etaTime)) { + // 18:34 -> 18:34:00 + // 18:34:00 -> 18:34:00 + String[] split = etaTime.split(":"); + if (split.length < 3) { + etaTime = etaTime + ":00"; + } else { + etaTime = split[0] + ":" + split[1] + ":" + split[2]; + } + } + BaseApiResponse submitResult = todoService.submitETA(etaTime, recordInfos, id); + + SysLogETA sysLogETA = new SysLogETA(); + java.util.Date now = new java.util.Date(); + + if(submitResult.isSuccess()) { + sysLogETA.setStatus(1); + result.setSuccess(true); +// result.setData(submitResult.getData()); + }else { + sysLogETA.setStatus(0); + result.setSuccess(false); + result.setCode(submitResult.getCode()); + } + + sysLogETA.setUserId(userId); + sysLogETA.setPlayerId(playerId); + sysLogETA.setInputDateTime(etaTime.substring(0, 5)); + sysLogETA.setCreatedAt(now); + sysLogETA.setUpdatedAt(now); + sysLogETAService.save(sysLogETA); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + @RequestMapping(value = "/app/todo/cancel_booking", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") + public ResponseEntity> cancelBooking(HttpServletRequest request, + @RequestBody TodoCancelBookingRequest cancelRequest) throws Exception { + LoginUserInfo loginUser = SysCommon.parseUserFromToken(request); + BaseApiResponse result = new BaseApiResponse<>(); + //-- + result.setRequestData(cancelRequest); + String userId = loginUser.getLoginId(); + String groupName = loginUser.getGroupName(); + //--get group permissions + boolean cancelBooking = true; + List userPermissions = sysGroupPermissionService.getRouterPermissionsByGroupName(groupName); + if(!userPermissions.isEmpty()) { + for(SysRouterPermission per:userPermissions) { + if(Strings.CS.equals(per.getId(), "10001_02") ) cancelBooking = true; + } + } + String playerId = cancelRequest.getPlayerId(); + BaseApiResponse findPlayerProfileResult = playerService.findPlayerProfileByPlayerIdAndUserId(playerId, userId); + if(findPlayerProfileResult.isSuccess()) { + PlayerProfileEntry profile = findPlayerProfileResult.getData(); + Integer code = profile.getCodedFlag(); + if(code==1 && cancelBooking) { + BaseApiResponse cancelResult = todoService.cancelBooking(cancelRequest,request); + if(cancelResult.isSuccess()) { + result.setSuccess(true); + result.setMessage(!StringUtils.isEmpty(cancelResult.getMessage())?cancelResult.getMessage():"Cancel Success"); + result.setData(cancelResult.getData()); + result.setRequestData(cancelResult.getData()); + }else { + result.setSuccess(false); + result.setMessage(cancelResult.getMessage()); + result.setCode(cancelResult.getCode()); + } + }else { + result.setSuccess(false); + result.setCode("NO_PERMISSION"); + result.setMessage("No permission to cancel"); + } + }else { + result.setSuccess(false); + result.setCode("CALL_API_ERROR"); + result.setMessage(findPlayerProfileResult.getMessage()); + } + return ResponseEntity.status(HttpStatus.OK).body(result); + } +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/BasePricePerDay.java b/src/main/java/com/mgm/mcrm/player/dtos/BasePricePerDay.java new file mode 100644 index 0000000..5ec7ff8 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/BasePricePerDay.java @@ -0,0 +1,11 @@ +package com.mgm.mcrm.player.dtos; + +import lombok.Data; + +@Data +public class BasePricePerDay { + + private Float amount; + private String currency; + +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/CancellationReasonResult.java b/src/main/java/com/mgm/mcrm/player/dtos/CancellationReasonResult.java new file mode 100644 index 0000000..260ef92 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/CancellationReasonResult.java @@ -0,0 +1,14 @@ +package com.mgm.mcrm.player.dtos; + +import lombok.Data; + +@Data +public class CancellationReasonResult { + + private String id; + private Long version; + private String zoneId; + private String code; + private Object description; + +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/PlayerProfile.java b/src/main/java/com/mgm/mcrm/player/dtos/PlayerProfile.java new file mode 100644 index 0000000..bfd4369 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/PlayerProfile.java @@ -0,0 +1,75 @@ +package com.mgm.mcrm.player.dtos; + +import java.util.ArrayList; +import java.util.List; + + +public class PlayerProfile { + + private String playerId; + private String name; + private String chineseName; + private String englishName; + private String tier; + private String salutation; + private boolean coded; + private List nameIds=new ArrayList(); + + public PlayerProfile() { + + } + + public String getPlayerId() { + return playerId; + } + public void setPlayerId(String playerId) { + this.playerId = playerId; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public String getTier() { + return tier; + } + public void setTier(String tier) { + this.tier = tier; + } + public String getSalutation() { + return salutation; + } + public void setSalutation(String salutation) { + this.salutation = salutation; + } + + 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 boolean isCoded() { + return coded; + } + + public void setCoded(boolean coded) { + this.coded = coded; + } + + public List getNameIds() { + return nameIds; + } + + public void setNameIds(List nameIds) { + this.nameIds = nameIds; + } +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/PlayerTPD.java b/src/main/java/com/mgm/mcrm/player/dtos/PlayerTPD.java new file mode 100644 index 0000000..a18765a --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/PlayerTPD.java @@ -0,0 +1,51 @@ +package com.mgm.mcrm.player.dtos; + + +public class PlayerTPD { + + private String playerId; + private String roomCategory; + private String bookingDate; + private Integer bookingDateQualificationFlag; + + + public PlayerTPD() { + + } + + public String getPlayerId() { + return playerId; + } + + public void setPlayerId(String playerId) { + this.playerId = playerId; + } + + public String getRoomCategory() { + return roomCategory; + } + + public void setRoomCategory(String roomCategory) { + this.roomCategory = roomCategory; + } + + public String getBookingDate() { + return bookingDate; + } + + public void setBookingDate(String bookingDate) { + this.bookingDate = bookingDate; + } + + public Integer getBookingDateQualificationFlag() { + return bookingDateQualificationFlag; + } + + public void setBookingDateQualificationFlag(Integer bookingDateQualificationFlag) { + this.bookingDateQualificationFlag = bookingDateQualificationFlag; + } + + + + +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/ProjectedRevenue.java b/src/main/java/com/mgm/mcrm/player/dtos/ProjectedRevenue.java new file mode 100644 index 0000000..ef5b4cc --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/ProjectedRevenue.java @@ -0,0 +1,9 @@ +package com.mgm.mcrm.player.dtos; + +import lombok.Data; + +@Data +public class ProjectedRevenue { + private String amount; + private String currency; +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/ProjectedRevenueAmount.java b/src/main/java/com/mgm/mcrm/player/dtos/ProjectedRevenueAmount.java new file mode 100644 index 0000000..19f5ae3 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/ProjectedRevenueAmount.java @@ -0,0 +1,12 @@ +package com.mgm.mcrm.player.dtos; + +import lombok.Data; + +@Data +public class ProjectedRevenueAmount { + private boolean isConfidential; + private Long gross; + private Long net; + private String currency; + private String basePriceType; +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/RatePricingDetail.java b/src/main/java/com/mgm/mcrm/player/dtos/RatePricingDetail.java new file mode 100644 index 0000000..5314170 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/RatePricingDetail.java @@ -0,0 +1,11 @@ +package com.mgm.mcrm.player.dtos; + +import lombok.Data; + +@Data +public class RatePricingDetail { + + private String roomTypeToChargeId; + private String ratePlanId; + +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/StatusCode.java b/src/main/java/com/mgm/mcrm/player/dtos/StatusCode.java new file mode 100644 index 0000000..28483f5 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/StatusCode.java @@ -0,0 +1,9 @@ +package com.mgm.mcrm.player.dtos; + +import lombok.Data; + +@Data +public class StatusCode { + private String code; + private String description; +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/UserInfo.java b/src/main/java/com/mgm/mcrm/player/dtos/UserInfo.java new file mode 100644 index 0000000..7e1f770 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/UserInfo.java @@ -0,0 +1,136 @@ +package com.mgm.mcrm.player.dtos; + +public class UserInfo { + + private String userId; + private String userName; + private String property; + private String division; + private String department; + private String section; + private String block; + private Long propertyId; + private Long divisionId; + private Long departmentId; + private Long sectionId; + private Long blockId; + private Long teamStructureId; + private boolean loginTag; + + public UserInfo() { + this.loginTag = false; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public Long getPropertyId() { + return propertyId; + } + + public void setPropertyId(Long propertyId) { + this.propertyId = propertyId; + } + + public Long getDivisionId() { + return divisionId; + } + + public void setDivisionId(Long divisionId) { + this.divisionId = divisionId; + } + + public Long getDepartmentId() { + return departmentId; + } + + public void setDepartmentId(Long departmentId) { + this.departmentId = departmentId; + } + + public Long getSectionId() { + return sectionId; + } + + public void setSectionId(Long sectionId) { + this.sectionId = sectionId; + } + + public Long getBlockId() { + return blockId; + } + + public void setBlockId(Long blockId) { + this.blockId = blockId; + } + + public String getProperty() { + return property; + } + + public void setProperty(String property) { + this.property = property; + } + + public String getDivision() { + return division; + } + + public void setDivision(String division) { + this.division = division; + } + + public String getDepartment() { + return department; + } + + public void setDepartment(String department) { + this.department = department; + } + + public String getSection() { + return section; + } + + public void setSection(String team) { + this.section = team; + } + + public String getBlock() { + return block; + } + + public void setBlock(String block) { + this.block = block; + } + + public boolean isLoginTag() { + return loginTag; + } + + public void setLoginTag(boolean loginTag) { + this.loginTag = loginTag; + } + + public Long getTeamStructureId() { + return teamStructureId; + } + + public void setTeamStructureId(Long teamStructureId) { + this.teamStructureId = teamStructureId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/request/EtaRecordInfo.java b/src/main/java/com/mgm/mcrm/player/dtos/request/EtaRecordInfo.java new file mode 100644 index 0000000..289c561 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/request/EtaRecordInfo.java @@ -0,0 +1,9 @@ +package com.mgm.mcrm.player.dtos.request; + +import lombok.Data; + +@Data +public class EtaRecordInfo { + private String hotelName; + private String confNo; +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/request/GetDashboardRequest.java b/src/main/java/com/mgm/mcrm/player/dtos/request/GetDashboardRequest.java new file mode 100644 index 0000000..69c0b74 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/request/GetDashboardRequest.java @@ -0,0 +1,8 @@ +package com.mgm.mcrm.player.dtos.request; + +import lombok.Data; + +@Data +public class GetDashboardRequest { + private String playerId; +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/request/GetTodoDetailRequest.java b/src/main/java/com/mgm/mcrm/player/dtos/request/GetTodoDetailRequest.java new file mode 100644 index 0000000..a7db94e --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/request/GetTodoDetailRequest.java @@ -0,0 +1,21 @@ +package com.mgm.mcrm.player.dtos.request; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class GetTodoDetailRequest { + + @JsonProperty("PlayerId") + private String playerId; + + @JsonProperty("TodoSegment") + private String todosegment; + + @JsonProperty("TodoCategory") + private String todoCategory; + + @JsonProperty("Date") + private String date; + +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/request/GetTodoListRequest.java b/src/main/java/com/mgm/mcrm/player/dtos/request/GetTodoListRequest.java new file mode 100644 index 0000000..01937d4 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/request/GetTodoListRequest.java @@ -0,0 +1,20 @@ +package com.mgm.mcrm.player.dtos.request; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class GetTodoListRequest { + + @JsonProperty("TodoSegment") + private String todoSegment; + + @JsonProperty("TodoCategory") + private String todoCategory; + + @JsonProperty("StartDate") + private String startDate; + + @JsonProperty("EndDate") + private String endDate; +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/request/TodoCancelBookingRequest.java b/src/main/java/com/mgm/mcrm/player/dtos/request/TodoCancelBookingRequest.java new file mode 100644 index 0000000..6f84c10 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/request/TodoCancelBookingRequest.java @@ -0,0 +1,19 @@ +package com.mgm.mcrm.player.dtos.request; + +import lombok.Data; + +import java.util.List; + +@Data +public class TodoCancelBookingRequest { + private Long id; + private String userId; + private String userName; + private String propertyName; + private String dlReservationId; + private String playerId; + private String confirmationNo; + + private List dlSharerIds; + private Long dlVersion; +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/request/TodoChangeDateRequest.java b/src/main/java/com/mgm/mcrm/player/dtos/request/TodoChangeDateRequest.java new file mode 100644 index 0000000..2055221 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/request/TodoChangeDateRequest.java @@ -0,0 +1,25 @@ +package com.mgm.mcrm.player.dtos.request; + +import com.mgm.mcrm.booking.dtos.BookingDateEntry; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +@Data +public class TodoChangeDateRequest { + private Long id; + private String confirmationNo; + private Date checkinDate; + private Date checkoutDate; + private Date checkInDate; + private Date checkOutDate; + private String userId; + private String userName; + private String playerId; + private String sharer; + private String remark; + private Long segmentId; + private List dateList; + private List extendDate; +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/request/TodoSubmitETARequest.java b/src/main/java/com/mgm/mcrm/player/dtos/request/TodoSubmitETARequest.java new file mode 100644 index 0000000..cdd278e --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/request/TodoSubmitETARequest.java @@ -0,0 +1,16 @@ +package com.mgm.mcrm.player.dtos.request; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +@Data +public class TodoSubmitETARequest { + + @JsonProperty("ETATime") + private String etaTime; + private String playerId; + private List recordInfo; + private Long id; +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/request/WebCheckPlayerTPDRequest.java b/src/main/java/com/mgm/mcrm/player/dtos/request/WebCheckPlayerTPDRequest.java new file mode 100644 index 0000000..e6e2cc0 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/request/WebCheckPlayerTPDRequest.java @@ -0,0 +1,16 @@ +package com.mgm.mcrm.player.dtos.request; + +import com.mgm.mcrm.booking.dtos.search.DateRange; +import lombok.Data; + +import java.util.List; + +@Data +public class WebCheckPlayerTPDRequest { + private String playerId; + private String roomCat; + private String bookingType; + private String property; + private List dates; + private List dateRange; +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/request/WebPlayerLookupRequest.java b/src/main/java/com/mgm/mcrm/player/dtos/request/WebPlayerLookupRequest.java new file mode 100644 index 0000000..7e5a4b6 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/request/WebPlayerLookupRequest.java @@ -0,0 +1,9 @@ +package com.mgm.mcrm.player.dtos.request; + +import lombok.Data; + +@Data +public class WebPlayerLookupRequest { + private String playerId; + private String userId; +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/response/CancelReasonResultResponse.java b/src/main/java/com/mgm/mcrm/player/dtos/response/CancelReasonResultResponse.java new file mode 100644 index 0000000..fd88fce --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/response/CancelReasonResultResponse.java @@ -0,0 +1,33 @@ +package com.mgm.mcrm.player.dtos.response; + +import com.mgm.mcrm.player.dtos.CancellationReasonResult; +import lombok.Data; + +import java.util.List; + +/** + * 对应外层返回的 JSON: + * { + * \"results\": { \"PropertyType\": [ ... ] }, + * \"paging\": { ... } + * } + */ +@Data +public class CancelReasonResultResponse { + + private ResultsWrapper results; + + private PagingResponse paging; + + @Data + public static class ResultsWrapper { + private List cancelReason; +} + + @Data + public static class PagingResponse { + private Integer pageNumber; + private Integer pageSize; + private Integer totalCount; + } +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/response/DaylightReservationResponse.java b/src/main/java/com/mgm/mcrm/player/dtos/response/DaylightReservationResponse.java new file mode 100644 index 0000000..d2225f0 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/response/DaylightReservationResponse.java @@ -0,0 +1,51 @@ +package com.mgm.mcrm.player.dtos.response; + +import com.mgm.mcrm.player.dtos.ProjectedRevenue; +import com.mgm.mcrm.player.dtos.ProjectedRevenueAmount; +import com.mgm.mcrm.player.dtos.StatusCode; +import lombok.Data; + +import java.util.List; + +@Data +public class DaylightReservationResponse { + private String id; + private String profileId; + private StatusCode statusCode; + private String confirmationNumber; + private String eta; + private String etd; + private String arrivalDate; + private String departureDate; + private String roomTypeId; + private String roomTypeToChargeId; + private String guaranteeTypeId; + private String sourceId; + private String channelId; + private boolean isRoomFixed; + private ProjectedRevenue projectedRevenue; + private Object transportations; + private String bookingDate; + private String accountId; + private Long version; + private String createdAt; + private String updatedAt; + private String updatedAtUtc; + private String createdAtUtc; + private ProjectedRevenueAmount projectedRevenueAmount; + private String bookingTimestamp; + private boolean walkInIntention; + private Object relations; + private boolean isRatePriceHidden; + private String blockId; + private List accompanyingGuestProfileIds; + + private List externalIds; + + @Data + public static class ExternalId { + + private String systemId; + private String number; + } +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/response/GetDashboardResponse.java b/src/main/java/com/mgm/mcrm/player/dtos/response/GetDashboardResponse.java new file mode 100644 index 0000000..c5725bb --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/response/GetDashboardResponse.java @@ -0,0 +1,12 @@ +package com.mgm.mcrm.player.dtos.response; + +import com.mgm.mcrm.common.dtos.mgm_api.TodoDashboardResult; +import lombok.Data; + +@Data +public class GetDashboardResponse { + private String errorCode; + private boolean isSuccess=false; + private String errorMessage=""; + private TodoDashboardResult returnData =null; +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/response/GetTodoDetailResponse.java b/src/main/java/com/mgm/mcrm/player/dtos/response/GetTodoDetailResponse.java new file mode 100644 index 0000000..20d8296 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/response/GetTodoDetailResponse.java @@ -0,0 +1,13 @@ +package com.mgm.mcrm.player.dtos.response; +import com.mgm.mcrm.common.dtos.mgm_api.TodoDetailResult; +import lombok.Data; + +@Data +public class GetTodoDetailResponse { + + private String errorCode; + private boolean isSuccess=false; + private String errorMessage=""; + private TodoDetailResult returnData =null; + +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/response/GetTodoListResponse.java b/src/main/java/com/mgm/mcrm/player/dtos/response/GetTodoListResponse.java new file mode 100644 index 0000000..20e290b --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/response/GetTodoListResponse.java @@ -0,0 +1,4 @@ +package com.mgm.mcrm.player.dtos.response; + +public class GetTodoListResponse { +} diff --git a/src/main/java/com/mgm/mcrm/player/dtos/response/ReservationResultResponse.java b/src/main/java/com/mgm/mcrm/player/dtos/response/ReservationResultResponse.java new file mode 100644 index 0000000..509bb23 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/dtos/response/ReservationResultResponse.java @@ -0,0 +1,32 @@ +package com.mgm.mcrm.player.dtos.response; + +import com.alibaba.fastjson.annotation.JSONField; +import com.mgm.mcrm.basesetting.property.dtos.response.DayLightProfileResponse; +import lombok.Data; + +/** + * 对应外层返回的 JSON: + * { + * \"results\": { \"PropertyType\": [ ... ] }, + * \"paging\": { ... } + * } + */ +@Data +public class ReservationResultResponse { + + private ResultsWrapper results; + + private PagingResponse paging; + + @Data + public static class ResultsWrapper { + private DaylightReservationResponse reservation; +} + + @Data + public static class PagingResponse { + private Integer pageNumber; + private Integer pageSize; + private Integer totalCount; + } +} diff --git a/src/main/java/com/mgm/mcrm/player/services/PlayerService.java b/src/main/java/com/mgm/mcrm/player/services/PlayerService.java new file mode 100644 index 0000000..df07e88 --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/services/PlayerService.java @@ -0,0 +1,400 @@ +package com.mgm.mcrm.player.services; + +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.parser.Feature; +import com.mgm.mcrm.appsetting.services.SysSettingService; +import com.mgm.mcrm.booking.dtos.search.DateRange; +import com.mgm.mcrm.booking.services.OperaDBBookingService; +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.PlayerProfileEntry; +import com.mgm.mcrm.common.dtos.mgm_api.PlayerTPDApiResult; +import com.mgm.mcrm.common.services.MGMApiService; +import com.mgm.mcrm.player.dtos.PlayerTPD; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +@Slf4j +@Service +public class PlayerService { + + @Resource + private MGMApiService mgmApiService; + + @Resource + private SysSettingService sysSettingService; + + @Resource + private OperaDBBookingService operaDBBookingService; + + public BaseApiResponse findPlayerProfileByPlayerIdAndUserId(String playerId, String userId) { + BaseApiResponse result = new BaseApiResponse<>(); + HttpResponseResult httpResult; + try { + // Daylight profile 调用不再需要 token,这里直接调用 MGM API + httpResult = mgmApiService.invokeGetPlayerProfile(playerId, userId); + + if (httpResult.getStatusCode() != 200) { + result.setSuccess(false); + result.setMessage("Invoke find player profile Failed:[" + httpResult.getStatusCode() + "] " + httpResult.getErrorMessage()); + return result; + } + + } catch (Exception err) { + result.setSuccess(false); + result.setMessage("Invoke find player profile API error:" + err.getMessage()); + return result; + } + + PlayerProfileEntry resultObj; + try { + resultObj = JSONObject.parseObject( + httpResult.getResponseContent(), + PlayerProfileEntry.class, + Feature.SupportNonPublicField, + Feature.IgnoreNotMatch + ); + + if (resultObj == null || resultObj.getStatusCode() == null) { + result.setSuccess(false); + result.setMessage("Invalid return data"); + return result; + } + } catch (Exception err) { + result.setSuccess(false); + result.setMessage("Parse return data failed:" + err.getMessage()); + return result; + } + + String resultCode = resultObj.getStatusCode(); + if (!"OK".equals(resultCode)) { + result.setSuccess(false); + result.setMessage(resultObj.getStatusDescription()); + return result; + } + + if (StringUtils.isEmpty(resultObj.getPlayerId())) { + result.setSuccess(false); + result.setMessage("Player not found"); + return result; + } + + resultObj.setName(resultObj.getEnglishName()); + this.supplementProfileNameIds(resultObj); + if (resultObj.getCodedFlag() == 0) { + resultObj = new PlayerProfileEntry(); + resultObj.setCodedFlag(0); + } + result.setSuccess(true); + result.setData(resultObj); + return result; + } + + public BaseApiResponse findWebPlayerProfileByPlayerId(String playerId) { + BaseApiResponse result = new BaseApiResponse<>(); + + HttpResponseResult httpResult; + try { + httpResult = mgmApiService.invokeGetAllPlayerProfile(playerId); + + if (httpResult.getStatusCode() != 200) { + result.setSuccess(false); + result.setMessage("Invoke find player profile Failed:[" + httpResult.getStatusCode() + "] " + httpResult.getErrorMessage()); + return result; + } + } catch (Exception err) { + result.setSuccess(false); + result.setMessage("Invoke find player profile API error:" + err.getMessage()); + return result; + } + + PlayerProfileEntry resultObj; + try { + resultObj = JSONObject.parseObject( + httpResult.getResponseContent(), + PlayerProfileEntry.class, + Feature.SupportNonPublicField, + Feature.IgnoreNotMatch + ); + + if (resultObj == null || resultObj.getStatusCode() == null) { + result.setSuccess(false); + result.setMessage("Invalid return data"); + return result; + } + + } catch (Exception err) { + result.setSuccess(false); + result.setMessage("Parse return data failed:" + err.getMessage()); + return result; + } + + String resultCode = resultObj.getStatusCode(); + if (!"OK".equals(resultCode)) { + result.setSuccess(false); + result.setMessage(resultObj.getStatusDescription()); + return result; + } + + if (StringUtils.isNotEmpty(resultObj.getPlayerId())) { + resultObj.setName(resultObj.getEnglishName()); + this.supplementProfileNameIds(resultObj); + result.setSuccess(true); + result.setData(resultObj); + } else { + result.setSuccess(false); + result.setMessage("Player not found"); + } + return result; + } + + public BaseApiResponse checkTPDByPlayerIdAndRoomAndDates( + String playerId, + String roomCate, + List dates, + String bookingType, + String property) { + BaseApiResponse result = new BaseApiResponse<>(); + + HttpResponseResult httpResult; + try { + httpResult = mgmApiService.invokeCheckPlayerTPD(playerId, roomCate, dates, bookingType, property); + + if (httpResult.getStatusCode() != 200) { + result.setSuccess(false); + result.setMessage("Invoke check player TPD Failed:[" + httpResult.getStatusCode() + "] " + httpResult.getErrorMessage()); + return result; + } + } catch (Exception err) { + result.setSuccess(false); + result.setMessage("Invoke check player TPD API error:" + err.getMessage()); + return result; + } + + PlayerTPDApiResult resultObj; + try { + resultObj = JSONObject.parseObject( + httpResult.getResponseContent(), + PlayerTPDApiResult.class, + Feature.SupportNonPublicField, + Feature.IgnoreNotMatch + ); + if (resultObj == null) { + result.setSuccess(false); + result.setMessage("Invalid return data"); + return result; + } + } catch (Exception err) { + result.setSuccess(false); + result.setMessage("Parse return data failed:" + err.getMessage()); + return result; + } + + String resultCode = resultObj.getStatusCode(); + if (!"OK".equals(resultCode)) { + result.setSuccess(false); + result.setMessage("CheckPlayerTPD API return error:[" + resultCode + "] " + resultObj.getStatusDescription()); + return result; + } + + List tpd = resultObj.getRecords(); + if (tpd == null) { + result.setSuccess(false); + result.setMessage("Player TPD not found"); + return result; + } + + int dateNum = tpd.size(); + int qualifyNum = 0; + int unQualifyNum = 0; + List resultList = new ArrayList<>(); + for (PlayerTPD t : tpd) { + if (t.getBookingDateQualificationFlag() == 1) { + ++qualifyNum; + } else { + ++unQualifyNum; + } + JSONObject obj = new JSONObject(); + String getDate = t.getBookingDate().replace("/", "-"); + obj.put("date", getDate); + obj.put("status", t.getBookingDateQualificationFlag() == 1 ? 0 : 1); + resultList.add(obj); + + } + if (dateNum == qualifyNum) { + resultObj.setStatus(0); + } else if (dateNum == unQualifyNum) { + resultObj.setStatus(1); + } else { + resultObj.setStatus(2); + } + int status = resultObj.getStatus(); + if (status == 2) { + if (dates.size() == 1) { + resultObj.setStatus(1); + resultObj.setDates(null); + } else if (dates.size() >= 2) { + if (SysCommon.mgmApiMockup) { + resultList = new ArrayList<>(); + for (int i = 0; i < dates.size(); i++) { + String date = dates.get(i); + JSONObject obj = new JSONObject(); + obj.put("date", date); + + if (i == 0) { + obj.put("status", 0); + } else if (i == 1) { + obj.put("status", 1); + } else { + Random rand = new Random(); + int randomStatus = rand.nextInt(2); + obj.put("status", randomStatus); + } + resultList.add(obj); + } + } + resultObj.setDates(resultList); + } + } + result.setSuccess(true); + result.setData(resultObj); + return result; + } + + public BaseApiResponse checkSecondTPDByPlayerIdAndRoomAndDates( + String playerId, + String roomCate, + List dateRange, + List dates, + String bookingType, + String property) { + BaseApiResponse result = new BaseApiResponse<>(); + + HttpResponseResult httpResult; + try { + httpResult = mgmApiService.invokeCheckPlayerSecondTPD(playerId, roomCate, dateRange, bookingType, property); + if (httpResult.getStatusCode() != 200) { + result.setSuccess(false); + result.setMessage("Invoke check player second TPD Failed:[" + httpResult.getStatusCode() + "] " + httpResult.getErrorMessage()); + return result; + } + } catch (Exception err) { + result.setSuccess(false); + result.setMessage("Invoke check player second TPD API error:" + err.getMessage()); + return result; + } + + PlayerTPDApiResult resultObj; + try { + resultObj = JSONObject.parseObject( + httpResult.getResponseContent(), + PlayerTPDApiResult.class, + Feature.SupportNonPublicField, + Feature.IgnoreNotMatch + ); + + if (resultObj == null) { + result.setSuccess(false); + result.setMessage("Invalid return data"); + return result; + } + } catch (Exception err) { + result.setSuccess(false); + result.setMessage("Parse return data failed:" + err.getMessage()); + return result; + } + + String resultCode = resultObj.getStatusCode(); + if (!"OK".equals(resultCode)) { + result.setSuccess(false); + result.setMessage("CheckPlayerSecondTPD API return error:[" + resultCode + "] " + resultObj.getStatusDescription()); + return result; + } + + List tpd = resultObj.getRecords(); + if (tpd == null) { + result.setSuccess(false); + result.setMessage("Player Second TPD not found"); + return result; + } + + int dateNum = tpd.size(); + int qualifyNum = 0; + int unQualifyNum = 0; + List resultList = new ArrayList<>(); + for (PlayerTPD t : tpd) { + if (t.getBookingDateQualificationFlag() == 1) { + ++qualifyNum; + } else { + ++unQualifyNum; + } + JSONObject obj = new JSONObject(); + String getDate = t.getBookingDate().replace("/", "-"); + obj.put("date", getDate); + obj.put("status", t.getBookingDateQualificationFlag() == 1 ? 0 : 1); + resultList.add(obj); + } + if (dateNum == qualifyNum) { + resultObj.setStatus(0); + } else if (dateNum == unQualifyNum) { + resultObj.setStatus(1); + } else { + resultObj.setStatus(2); + } + int status = resultObj.getStatus(); + if (status == 2) { + if (dates != null && dates.size() == 1) { + resultObj.setStatus(1); + resultObj.setDates(null); + } else if (dates != null && dates.size() >= 2) { + if (SysCommon.mgmApiMockup) { + resultList = new ArrayList<>(); + for (int i = 0; i < dates.size(); i++) { + String date = dates.get(i); + JSONObject obj = new JSONObject(); + obj.put("date", date); + + if (i == 0) { + obj.put("status", 0); + } else if (i == 1) { + obj.put("status", 1); + } else { + Random rand = new Random(); + int randomStatus = rand.nextInt(2); + obj.put("status", randomStatus); + } + resultList.add(obj); + } + } + resultObj.setDates(resultList); + } + } + result.setSuccess(true); + result.setData(resultObj); + + return result; + } + + private void supplementProfileNameIds(PlayerProfileEntry profile) { + boolean isMock = sysSettingService.isMockReplicate(); + if (isMock) { + List lists = new ArrayList<>(); + lists.add(710825); + profile.setNameIds(lists); + } else { + List lists = operaDBBookingService.getOperaNameIDByPlayerID(profile.getPlayerId()); + List nameList = new ArrayList<>(); + if (lists != null && !lists.isEmpty()) { + nameList.add(Integer.valueOf(lists.getFirst())); + } + profile.setNameIds(nameList); + } + } +} diff --git a/src/main/java/com/mgm/mcrm/player/services/TodoService.java b/src/main/java/com/mgm/mcrm/player/services/TodoService.java new file mode 100644 index 0000000..3a01f6c --- /dev/null +++ b/src/main/java/com/mgm/mcrm/player/services/TodoService.java @@ -0,0 +1,989 @@ +package com.mgm.mcrm.player.services; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.parser.Feature; +import com.google.gson.Gson; +import com.mgm.mcrm.appsetting.models.CfgSettings; +import com.mgm.mcrm.appsetting.services.SettingService; +import com.mgm.mcrm.appsetting.services.SysSettingService; +import com.mgm.mcrm.authorization.dtos.LoginUserInfo; +import com.mgm.mcrm.basesetting.daylight.dtos.response.ReservationDoorKeyResponse; +import com.mgm.mcrm.basesetting.daylight.dtos.response.ReservationQueueResponse; +import com.mgm.mcrm.basesetting.daylight.services.DaylightService; +import com.mgm.mcrm.basesetting.property.models.CfgProperties; +import com.mgm.mcrm.basesetting.property.repositories.PropertyDao; +import com.mgm.mcrm.basesetting.room.models.CfgOtherRoomStatus; +import com.mgm.mcrm.basesetting.room.repositories.OtherRoomStatusDao; +import com.mgm.mcrm.basesetting.room.services.OtherRoomStatusService; +import com.mgm.mcrm.booking.controllers.BookingController; +import com.mgm.mcrm.booking.dtos.BookingDto; +import com.mgm.mcrm.booking.dtos.opera.CancelBookingRequest; +import com.mgm.mcrm.booking.dtos.opera.FetchBookingRequest; +import com.mgm.mcrm.booking.dtos.opera.GuestRequestsRequest; +import com.mgm.mcrm.booking.dtos.opera.ModifyBookingRequest; +import com.mgm.mcrm.booking.mappers.BookingMapper; +import com.mgm.mcrm.booking.models.Bookings; +import com.mgm.mcrm.booking.models.BookingsView; +import com.mgm.mcrm.booking.repositories.BookingDao; +import com.mgm.mcrm.booking.repositories.BookingViewDao; +import com.mgm.mcrm.booking.services.*; +import com.mgm.mcrm.common.constants.SysCommon; +import com.mgm.mcrm.common.constants.SysConstants; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.common.dtos.http_util.HttpResponseResult; +import com.mgm.mcrm.common.dtos.mgm_api.*; +import com.mgm.mcrm.common.services.HttpService; +import com.mgm.mcrm.common.services.MGMApiService; +import com.mgm.mcrm.common.utils.DateTimeUtil; +import com.mgm.mcrm.common.utils.LogUtil; +import com.mgm.mcrm.common.utils.SendEmail; +import com.mgm.mcrm.logging.models.SysLogBooking; +import com.mgm.mcrm.logging.services.SysLogBookingService; +import com.mgm.mcrm.notification.models.Email; +import com.mgm.mcrm.notification.repositories.EmailDao; +import com.mgm.mcrm.player.dtos.request.EtaRecordInfo; +import com.mgm.mcrm.player.dtos.request.TodoCancelBookingRequest; +import com.mgm.mcrm.player.dtos.request.TodoChangeDateRequest; +import com.mgm.mcrm.player.dtos.response.GetDashboardResponse; +import com.mgm.mcrm.player.dtos.response.GetTodoDetailResponse; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Strings; +import org.springframework.stereotype.Service; + +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.util.*; +import java.util.concurrent.TimeUnit; + +@Slf4j +@Service +public class TodoService { + + @Resource + private MGMApiService mgmApiService; + + @Resource + private SysSettingService sysSettingService; + + @Resource + private OperaDBBookingService operaDBBookingService; + + @Resource + private BookingDao bookingDao; + + @Resource + private BookingViewDao bookingViewDao; + + @Resource + private PropertyDao propertyDao; + + @Resource + private OtherRoomStatusDao otherRoomStatusDao; + + @Resource + OperaService operaService; + + @Resource + private NonMGMBookingService otherBookingService; + + @Resource + private SettingService settingService; + + @Resource + private EmailDao emailDao; + + @Resource + private OtherRoomStatusService otherRoomStatusService; + + @Resource + private SysLogBookingService sysLogBookingService; + + @Resource + private OtherRoomStatusDao roomStatusDao; + + @Resource + private WaitlistBookingService waitlistBookingService; + + @Resource + private PlayerService playerService; + + @Resource + private HttpService httpService; + @Resource + private BookingService bookingService; + + @Resource + private DaylightService dlService; + + @Resource + private BookingMapper bookingMapper; + + public GetDashboardResponse getTodoDashboard(String userId) throws Exception { + GetDashboardResponse result = new GetDashboardResponse(); + + try { + HttpResponseResult httpResult = mgmApiService.invokeGetTodoDashboard(userId, 0); + try { + TodoDashboardResult resultObj = JSONObject.parseObject(httpResult.getResponseContent(), TodoDashboardResult.class, Feature.SupportNonPublicField, Feature.IgnoreNotMatch); + if (Strings.CI.equals(resultObj.getStatusCode(), "OK")) { + result.setSuccess(true); + result.setReturnData(resultObj); + } else { + result.setSuccess(false); + result.setErrorCode(resultObj.getStatusDescription()); + LogUtil.info(TodoService.class, "[GetDashboardData Error]" + resultObj.getStatusDescription()); + + } + } catch (Exception err) { + result.setSuccess(false); + result.setErrorCode("RETURN_DATA_ERROR"); + LogUtil.info(TodoService.class, "[GetDashboardData Error]" + err.getMessage()); + } + + } catch (Exception err) { + result.setSuccess(false); + result.setErrorCode("INVOKE_TODODASHBOARD_API_ERROR"); + LogUtil.info(TodoService.class, "[GetDashboardData Error]" + err.getMessage()); + } + + return result; + } + + public GetTodoDetailResponse getTodoDetail(String playerId, String todoCategory, String todoSegment, String date) throws Exception { + GetTodoDetailResponse result = new GetTodoDetailResponse(); + try { + HttpResponseResult httpResult = mgmApiService.invokeGetTodoDetail(playerId, todoCategory, todoSegment, date, 1); + try { + TodoDetailResult resultObj = JSONObject.parseObject(httpResult.getResponseContent(), TodoDetailResult.class, Feature.SupportNonPublicField, Feature.IgnoreNotMatch); + if (Strings.CI.equals(resultObj.getStatusCode(), "OK")) { + + + // TODO daylight专用,后面要改 by Mauve + if (1 == 1) { + if (resultObj.getDescriptions() != null) { + for (TodoDetailDescription detailRecord : resultObj.getDescriptions()) { + if ("Room".equalsIgnoreCase(detailRecord.getItemRecordType())) { + String recordDesc = detailRecord.getItemRecordDescription(); + if (StringUtils.isNotBlank(recordDesc)) { + String confNum = null; + int index = recordDesc.indexOf("Conf#"); + if (index != -1) { + String sub = recordDesc.substring(index + 5); + int pipeIndex = sub.indexOf("|"); + if (pipeIndex != -1) { + confNum = sub.substring(0, pipeIndex).trim(); + } else { + confNum = sub.trim(); + } + } + + 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); + if ("Inhouse".equalsIgnoreCase(todoCategory)) { + 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) { + detailRecord.setItemRecordDescription(recordDesc.replace("Conf#" + confNum, "Conf#" + 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) { + detailRecord.setItemRecordDescription(recordDesc.replace("Conf#" + confNum, "Conf#" + confNum + " [In Queue]")); + } + } + } + } + } + } + } + } + } + } + + result.setSuccess(true); + result.setReturnData(resultObj); + } else { + result.setSuccess(false); + result.setErrorCode(resultObj.getStatusDescription()); + } + } catch (Exception err) { + result.setSuccess(false); + result.setErrorCode("RETURN_DATA_ERROR"); + LogUtil.info(TodoService.class, "[GetTodoDetail Error]" + err.getMessage()); + } + + } catch (Exception err) { + result.setSuccess(false); + result.setErrorCode("INVOKE_TODOLISTDETAIL_API_ERROR"); + LogUtil.info(TodoService.class, "[GetTodoDetail Error]" + err.getMessage()); + } + + return result; + } + + public BaseApiResponse cancelBooking(TodoCancelBookingRequest param, HttpServletRequest request) throws Exception { + BaseApiResponse processResult= new BaseApiResponse<>(); + Long bookId = param.getId(); + String oStatus = ""; + + if (bookId == null) { + processResult.setSuccess(false); + processResult.setMessage("No Booking Id."); + processResult.setData(param); + + return processResult; + } + + Gson gson = new Gson(); + BookingsView bookingView = bookingViewDao.findById(bookId).orElse(null); + boolean isMock =sysSettingService.isMockReplicate(); + String userId = param.getUserId(); + String userName = param.getUserName(); + String category = bookingView.getPropertyCategory(); + boolean isOpera = Strings.CS.equals("OPERA", category); + boolean isDaylight = Strings.CS.equals("DAYLIGHT", category); + boolean isOther = Strings.CS.equals("OTHER", category); + + CfgProperties property = propertyDao.getByName(param.getPropertyName()); + + String dlReservationId = null; + + if (Strings.CS.equals(category,"DAYLIGHT")) { + dlReservationId = param.getDlReservationId(); + } + + if (isOther) { + // CancelOtherBooking Flow +// 获取setting表Cancel状态和时间区间 + CfgSettings enAbleCancel = settingService.getSettingByKey("CAN_CANCEL_OTHERBOOKING"); + +// 判断状态是否启用 + if(Strings.CS.equals(enAbleCancel.getKeyValues(), "1")) { +// 方法启用(==1),判断时间 +// 状态启用判断现在时间是否再时间区间内 + if(isPassTimeNow()) { + //Cancel Non MGM Booking + Bookings obooking = cancelOtherBooking(bookId,request); + if(obooking != null) { + processResult.setSuccess(true); + processResult.setData(bookingView); + }else { + processResult.setSuccess(false); + processResult.setCode("SYSTEM_ERROR"); + processResult.setMessage("System error"); + } + }else { + processResult.setSuccess(false); + processResult.setCode("ERR_CANCEL_TIME"); + processResult.setData(param); + } + }else{ +// 如果enAbleCancel方法没有启用(==0)直接cancelbooking + //Cancel Non MGM Booking + Bookings obooking = cancelOtherBooking(bookId,request); + if(obooking != null) { + processResult.setSuccess(true); + processResult.setData(bookingView); + }else { + processResult.setSuccess(false); + processResult.setCode("SYSTEM_ERROR"); + processResult.setMessage("System error"); + } + } + + return processResult; + } + + // 如果是模拟数据 + if(isMock) { + Bookings booking = bookingDao.findById(bookId).orElse(null); + booking.setApproveStatus("C"); + booking.setLastOperaStatus("CANCELED"); + booking.setChangeCheckinDate(null); + booking.setChangeCheckoutDate(null); + bookingDao.save(booking); + processResult.setSuccess(true); + processResult.setData(booking); + TimeUnit.SECONDS.sleep(1L); + if (isDaylight) { + dlService.daylightCancelReservationNew( + dlReservationId, + property.getDlPropertyId(), + param.getDlSharerIds(), + param.getDlVersion() + ); + } + + return processResult; + } + + if (isDaylight) { + Date newDate = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + Bookings booking = bookingDao.findById(bookId).orElse(null); + + booking.setApproveStatus("C"); + booking.setLastOperaStatus("CANCELED"); + booking.setCancelledBy(userId); + booking.setCancelledAt(newDate); + booking.setUpdatedAt(newDate); + booking.setUpdatedBy(userId); + bookingDao.save(booking); + + BaseApiResponse cancelResult = + dlService.daylightCancelReservationNew( + dlReservationId, + property.getDlPropertyId(), + param.getDlSharerIds(), + param.getDlVersion() + ); + + if (cancelResult.isSuccess()) { + LogUtil.info(TodoService.class, "[Cancel Booking] Cancel Success, bookingId=" + bookId); + processResult.setSuccess(true); + processResult.setData(dlReservationId); + }else { + LogUtil.warn(TodoService.class, "[Cancel Booking] Cancel Fail"); + booking.setUpdatedAt(newDate); + booking.setCreatedAt(newDate); + booking.setApproveStatus("F"); + booking.setErrorMessage("Call Daylight CANCEL_RESERVATION fail,Fail reason: "+cancelResult.getMessage()); + bookingDao.save(booking); + processResult.setSuccess(false); + processResult.setData(cancelResult.getMessage()); + } + + return processResult; + } + + if (isOpera) { + boolean hasShare = false; + List shareConfList = new ArrayList(); + JSONObject fetchResponse = new JSONObject(); + FetchBookingRequest owsReq = new FetchBookingRequest(); + owsReq.setConfirmationNo(bookingView.getConfirmationNo()); + fetchResponse = operaService.fetchBooking(owsReq); + if(fetchResponse.containsKey("shareConfList")) { + shareConfList = (List) fetchResponse.get("shareConfList"); + hasShare = true; + } + CancelBookingRequest cancelRequest = new CancelBookingRequest(); + JSONObject cancelResponse = new JSONObject(); + cancelRequest.setHotelCode(bookingView.getHotelCode()); + cancelRequest.setConfirmationNo(bookingView.getConfirmationNo()); + LogUtil.info(BookingController.class, "[cancelBooking] cancelRequest begin" + gson.toJson(cancelRequest)); + cancelResponse = operaService.cancelBooking(cancelRequest); + LogUtil.info(BookingController.class, + "[cancelBooking] Cancel Booking res" + gson.toJson(cancelResponse)); + JSONObject errors = new JSONObject(); + + //cancel share booking + if (shareConfList!=null) { + for (int a = 0; a < shareConfList.size(); a++) { + String shareConfirmationNo = String.valueOf(shareConfList.get(a)); + if(!StringUtils.isEmpty(shareConfirmationNo)) { + cancelRequest = new CancelBookingRequest(); + cancelResponse = new JSONObject(); + cancelRequest.setHotelCode(bookingView.getHotelCode()); + cancelRequest.setConfirmationNo(shareConfirmationNo); + cancelResponse = operaService.cancelBooking(cancelRequest); + } + } + } + if (cancelResponse != null) { + processResult.setSuccess(true); + processResult.setData(bookingView); + }else { + Date newDate = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + Bookings booking = bookingDao.findById(bookId).orElse(null); + errors = cancelResponse; + booking.setUpdatedAt(newDate); + booking.setCreatedAt(newDate); + booking.setApproveStatus("F"); + booking.setErrorMessage(errors.getString("message")); + processResult.setSuccess(false); + processResult.setMessage(errors.getString("message")!=null?errors.getString("message"):"System Error"); + processResult.setCode("SYSTEM_ERROR"); + processResult.setData(bookingView); + } + + return processResult; + } + + processResult.setSuccess(false); + processResult.setMessage("Cancel booking fail, invalid property"); + + return processResult; + } + + public BaseApiResponse getTodoList(String userId, String category, String type, Date startDate, Date endDate) throws Exception { + BaseApiResponse result = new BaseApiResponse<>(); + + HttpResponseResult httpResult; + try { + // TODO 这里现在写死只拿daylight的todolist,后面会要拿到Opera的todoList,这个时候要改成两个都拿 by Mauve + httpResult = mgmApiService.invokeGetTodoList(userId, category, type, startDate, endDate, 1); + } catch (Exception err) { + result.setSuccess(false); + result.setCode("INVOKE_TODOLISTDETAIL_API_ERROR"); + LogUtil.info(TodoService.class, "[GetTodoList Error]" + err.getMessage()); + return result; + } + + try { + TodoListResult resultObj = JSONObject.parseObject( + httpResult.getResponseContent(), + TodoListResult.class, + Feature.SupportNonPublicField, + Feature.IgnoreNotMatch + ); + if ("OK".equals(resultObj.getStatusCode())) { + List recordList = resultObj.getRecords(); + TodoDateListResult dateResult = new TodoDateListResult(); + Map dateMap = new LinkedHashMap<>(); + for (TodoListRecord record : recordList) { + if (!dateMap.containsKey(record.getDate())) { + TodoDateListRecord dateRecord = new TodoDateListRecord(); + dateRecord.setDate(record.getDate()); + dateRecord.setDateRecords(new ArrayList<>()); + dateMap.put(record.getDate(), dateRecord); + } + dateMap.get(record.getDate()).getDateRecords().add(record); + } + List dateList = new ArrayList<>(dateMap.values()); + + // TODO daylight专用,后面要改 by Mauve + if (1 == 1) { + for (TodoDateListRecord todoDateListRecord : dateList) { + + List dateRecords = todoDateListRecord.getDateRecords(); + + for (TodoListRecord record : dateRecords) { + String daylightConfirmationNo = record.getOperaConfirmationNo(); + + try { + String[] split = daylightConfirmationNo.split(","); + + for (String temp2 : split) { + String[] split1 = temp2.split(";"); + + String confNum = split1[split1.length - 1]; + + 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]); + } + } + } + } catch (Exception e) { + log.warn("Failed to set ETA, operaConfirmationNo={}", daylightConfirmationNo, e); + } + } + } + dateResult.setRecords(dateList); + } + + result.setSuccess(true); + result.setData(dateResult); + } else { + result.setSuccess(false); + result.setCode(resultObj.getStatusDescription()); + } + } catch (Exception err) { + result.setSuccess(false); + result.setCode("RETURN_DATA_ERROR"); + LogUtil.info(TodoService.class, "[GetTodoList Error]" + err.getMessage()); + } + return result; + } + + public BaseApiResponse submitETA(String etaTime, List recordInfos, Long id) throws Exception { + + BaseApiResponse result = new BaseApiResponse<>(); + boolean isMock = sysSettingService.isMockReplicate(); + if (StringUtils.isBlank(etaTime) || CollectionUtils.isEmpty(recordInfos)) { + return missParameter(result); + } + + for (EtaRecordInfo recordInfo : recordInfos) { + result = handleSingleRecord(etaTime, recordInfo, isMock, id); // 保持原逻辑:最终返回最后一条 + } + return result; + } + + private BaseApiResponse handleSingleRecord( + String etaTime, + EtaRecordInfo recordInfo, + boolean isMock, + Long id) throws Exception { + + BaseApiResponse result = new BaseApiResponse<>(); + + String hotelName = StringUtils.trim(recordInfo.getHotelName()); + String confNo = StringUtils.trim(recordInfo.getConfNo()); + + if (StringUtils.isBlank(hotelName) || StringUtils.isBlank(confNo)) { + return missParameter(result); + } + + CfgProperties property = propertyDao.getByLikeName(hotelName); + if (property == null) { + return noRecord(result); + } + + String category = property.getCategory(); + + if (Strings.CI.equals("DAYLIGHT", category)) { + return handleDaylightETA(etaTime, confNo, property, id); + } + + if (Strings.CI.equals("OPERA", category)) { + return handleOperaETA(etaTime, confNo, property, isMock); + } + + if (Strings.CI.equals("OTHER", category)) { + return handleOtherETA(etaTime, confNo, property); + } + + return noRecord(result); + } + + private BaseApiResponse handleOperaETA( + String etaTime, + String confNo, + CfgProperties property, + boolean isMock) throws Exception { + + BaseApiResponse result = new BaseApiResponse<>(); + Gson gson = new Gson(); + + Bookings booking = new Bookings(); + booking.setConfirmationNo(confNo); + booking.setHotelCode(property.getHotelCode()); + booking.setCategory("OPERA"); + + ModifyBookingRequest request = new ModifyBookingRequest(); + request.setEta(etaTime); + request.setBooking(booking); + + LogUtil.info(TodoService.class, + "[submitETA] OPERA submit begin " + gson.toJson(request)); + + if (isMock) { + // mock 环境:直接操作 DB + Bookings editBooking = bookingDao.getByConfNoForETA(confNo, property.getId()); + if (editBooking == null) { + return noRecord(result); + } + + editBooking.setEta(etaTime); + bookingDao.save(editBooking); + result.setSuccess(true); + result.setData(editBooking); + return result; + } + + // dev / prod:调用 OPERA 接口 + JSONObject response = operaService.modifyETA(request); + + LogUtil.info(TodoService.class, + "[submitETA] OPERA submit res " + gson.toJson(response)); + + if (!response.containsKey("message")) { + result.setSuccess(true); + result.setData(booking); + } else { + result.setSuccess(false); + result.setCode(response.getString("message")); + result.setData(booking); + } + + return result; + } + + private BaseApiResponse handleDaylightETA( + String etaTime, + String confNo, + CfgProperties property, + Long id) throws Exception { + + BaseApiResponse result = new BaseApiResponse<>(); + + Bookings booking; + if (id != null) { + booking = bookingDao.findById(id).orElse(null); + } else { + booking = bookingDao.getByConfNoForETA(confNo, property.getId()); + } + + booking.setEta(etaTime); + + bookingDao.save(booking); + + if (StringUtils.isNotBlank(confNo)) { + + LogUtil.info(TodoService.class, "[submitETA] DAYLIGHT submit res"); + + BaseApiResponse> submitEta = + bookingService.callDaylightUpsertReservation(booking, "SUBMIT_ETA"); + + if (submitEta.isSuccess()) { + result.setSuccess(true); + result.setMessage(submitEta.getMessage()); + } else { + result.setSuccess(false); + result.setMessage(submitEta.getMessage()); + } + + return result; + } + + return noRecord(result); + } + + private BaseApiResponse handleOtherETA( + String etaTime, + String confNo, + CfgProperties property) { + + BaseApiResponse result = new BaseApiResponse<>(); + + Bookings editBooking = bookingDao.getByConfNoForETA(confNo, property.getId()); + if (editBooking == null) { + return noRecord(result); + } + + LogUtil.info(TodoService.class, "[submitETA] OTHER submit res"); + + editBooking.setEta(etaTime); + editBooking.setCategory("OTHER"); + bookingDao.save(editBooking); + + result.setSuccess(true); + result.setData(editBooking); + return result; + } + + private BaseApiResponse missParameter(BaseApiResponse result) { + result.setSuccess(false); + result.setCode("MISS_PARAMETER"); + result.setMessage("Miss Parameter"); + return result; + } + + private BaseApiResponse noRecord(BaseApiResponse result) { + result.setSuccess(false); + result.setCode("NO_RECORD"); + result.setMessage("There are no corresponding booking records."); + return result; + } + + public BaseApiResponse changeBookingDate(TodoChangeDateRequest param, HttpServletRequest request) throws Exception { + BaseApiResponse processResult = new BaseApiResponse<>(); + Long bookId = param.getId(); + String confNo = param.getConfirmationNo(); + String ciDate = DateTimeUtil.getDateByFormat(param.getCheckinDate(), "yyyy-MM-dd"); + String coDate = DateTimeUtil.getDateByFormat(param.getCheckoutDate(), "yyyy-MM-dd"); + String userId = param.getUserId(); + String userName = param.getUserName(); + String playerId = param.getPlayerId(); + PlayerProfileEntry profile = null; + BaseApiResponse res = playerService.findPlayerProfileByPlayerIdAndUserId(playerId, userId); + if (res.isSuccess()) { + profile = res.getData(); + } + if (bookId != null) { + Gson gson = new Gson(); + BookingsView bookingView; + if (confNo != null) { + List bookingsViews = bookingViewDao.findByConfirmationNo(confNo); + bookingView = bookingsViews.getFirst(); + } else { + bookingView = bookingViewDao.findById(bookId).orElse(null); + } + if (bookingView == null) { + processResult.setSuccess(false); + processResult.setMessage("Booking not found"); + log.warn("booking not found"); + return processResult; + } + Bookings booking = bookingDao.findById(bookingView.getId()).orElse(null); + boolean isMock = sysSettingService.isMockReplicate(); + Date checkinDate = DateTimeUtil.getDateFromString(ciDate, "yyyy-MM-dd"); + Date checkoutDate = DateTimeUtil.getDateFromString(coDate, "yyyy-MM-dd"); + + if ("DAYLIGHT".equals(bookingView.getPropertyCategory())) { + //Change Daylight Booking + + booking.setCheckinDate(checkinDate); + booking.setCheckoutDate(checkoutDate); + bookingDao.save(booking); + processResult.setSuccess(true); + processResult.setData(bookingMapper.entityToDto(booking)); + bookingService.daylightReservationChangeDate(param, profile, false); + + LogUtil.info(TodoService.class, "[ChangeBookingDate] ID:"+bookingView.getDlReservationId()); + + return processResult; + + } else if ("OPERA".equalsIgnoreCase(bookingView.getPropertyCategory())) { + boolean hasShare = false; + JSONObject fetchResponse = new JSONObject(); + FetchBookingRequest owsReq = new FetchBookingRequest(); + owsReq.setConfirmationNo(bookingView.getConfirmationNo()); + fetchResponse = operaService.fetchBooking(owsReq); + if (fetchResponse.containsKey("shareConfList")) { + hasShare = true; + } + if (hasShare) { + //sendEmail + Email email = new Email(); + email.setBookId(booking.getId()); + email.setCreatedAt(DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss")); + email.setCreatedBy(userId); + booking.setChangeCheckinDate(ciDate); + booking.setChangeCheckoutDate(coDate); + bookingView = this.getEmailInfo(bookingView, userId); + CfgSettings emailAddress = settingService.getSettingByKey(SysConstants.MGM_EMAIL_ADDRESS); + email = SendEmail.sendCancelEmail(booking, bookingView, email, userId, userName, emailAddress.getKeyValues()); + if (email.getStatus() == 1) { + processResult.setSuccess(true); + } else { + processResult.setSuccess(false); + processResult.setCode("Send Email Failed."); + } + emailDao.save(email); + processResult.setData(bookingMapper.entityToDto(booking)); + return processResult; + } + ModifyBookingRequest modifyBookingRequest = new ModifyBookingRequest(); + JSONObject modifyBookingResponse = new JSONObject(); + booking.setCheckinDate(checkinDate); + booking.setCheckoutDate(checkoutDate); + modifyBookingRequest.setBooking(booking); + LogUtil.info(TodoService.class, "[changeBookingDate] changeBookingDate begin" + gson.toJson(modifyBookingRequest)); + modifyBookingResponse = operaService.changeBookingDate(modifyBookingRequest); + LogUtil.info(TodoService.class, + "[changeBookingDate] Change Booking res" + gson.toJson(modifyBookingResponse)); + JSONObject errors = new JSONObject(); + if (!modifyBookingResponse.containsKey("message")) { + String bookComment = operaService.makeChangeDateComment(booking); + CfgProperties property = propertyDao.getById(booking.getPropertyId()); + GuestRequestsRequest changeDateCommentRequest = new GuestRequestsRequest(); + JSONObject changeDateCommentResponse = new JSONObject(); + changeDateCommentRequest.setActionType("ADD"); + changeDateCommentRequest.setProperty(property); + changeDateCommentRequest.setComment(bookComment); + changeDateCommentRequest.setConfirmationNo(booking.getConfirmationNo()); + changeDateCommentRequest.setCommentType("CASHIER"); + changeDateCommentResponse = operaService.guestRequests(changeDateCommentRequest); + processResult.setSuccess(true); + processResult.setData(bookingMapper.entityToDto(booking)); + } else { + Date newDate = DateTimeUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"); + String errorMsg = errors.getString("message") != null ? errors.getString("message") : "System Error"; + errors = modifyBookingResponse; + booking.setUpdatedAt(newDate); + booking.setCreatedAt(newDate); + booking.setApproveStatus("F"); + booking.setTryTime(5); + booking.setErrorMessage("Cancel booking fail.Error Message [ " + errorMsg + " ] "); + bookingDao.save(booking); + processResult.setSuccess(false); + processResult.setMessage(errors.getString("message") != null ? errors.getString("message") : "System Error"); + processResult.setCode("SYSTEM_ERROR"); + processResult.setData(bookingMapper.entityToDto(booking)); + } + } else { +// 获取setting表Cancel状态和时间区间 + CfgSettings enAbleCancel = settingService.getSettingByKey("CAN_CANCEL_OTHERBOOKING"); +// 判断状态是否启用 + if (Strings.CS.equals(enAbleCancel.getKeyValues(), "1")) { +// 方法启用(==1),判断时间 +// 状态启用判断现在时间是否再时间区间内 + if (isPassTimeNow()) { + //Change Non MGM Booking + Bookings obooking = changeOtherBooking(bookId, ciDate, coDate, request); + if (obooking != null) { + processResult.setSuccess(true); + processResult.setData(bookingMapper.entityToDto(obooking)); + } else { + processResult.setSuccess(false); + processResult.setCode("SYSTEM_ERROR"); + processResult.setMessage("System error"); + } + } else { + processResult.setSuccess(false); + processResult.setCode("ERR_CANCEL_TIME"); + processResult.setData(bookingMapper.changeDateRequestToDto(param)); + } + } else { +// 如果enAbleCancel方法没有启用(==0)直接changedate + //Change Non MGM Booking + Bookings obooking = changeOtherBooking(bookId, ciDate, coDate, request); + if (obooking != null) { + processResult.setSuccess(true); + processResult.setData(bookingMapper.entityToDto(obooking)); + } else { + processResult.setSuccess(false); + processResult.setCode("SYSTEM_ERROR"); + processResult.setMessage("System error"); + } + } + } + } else { + processResult.setSuccess(false); + processResult.setCode("No Booking Id."); + processResult.setData(bookingMapper.changeDateRequestToDto(param)); + } + + return processResult; + } + + private Bookings cancelOtherBooking(Long bookId, HttpServletRequest request) { + Bookings oBooking = bookingDao.findById(bookId).orElse(null); + CfgOtherRoomStatus roomStatus = roomStatusDao.findByStatusName("Pending Cancel"); + SysLogBooking logBooking = new SysLogBooking(); + LoginUserInfo userInfo = SysCommon.parseUserFromToken(request); + String oStatus = oBooking.getLastOperaStatus(); + Date now = new Date(); +// CfgOtherRoomStatus roomStatus = +// oBooking.setCheckinDate(checkinDate); +// oBooking.setCheckinDate(checkoutDate); + oBooking.setOtherRoomStatusId(roomStatus.getId()); + oBooking.setLastOperaStatus("Pending Cancel"); + oBooking.setOtherFollowUpStatusId(Long.valueOf("5")); + LogUtil.info(BookingController.class, + "[changeBookingDate] Start Cancel Other Booking BookingId = " + oBooking.getId()); + bookingDao.save(oBooking); +// 写入Audit Trail + logBooking.setOccurTime(now); + logBooking.setBookId(oBooking.getId()); + logBooking.setEventCode("Room Status"); + logBooking.setChangeFrom(oStatus); + logBooking.setChangeTo("Pending Cancel(CANCEL BOOKING)"); + logBooking.setLoginId(userInfo.getLoginId()); + logBooking.setLoginName(userInfo.getLoginId()); + sysLogBookingService.save(logBooking); + +// otherBookingService.processOtherAllotment(oBooking.getRoomId(), checkoutDate, +// checkinDate, oBooking.getPropertyId(), oBooking.getSegmentId()); + return oBooking; + } + + private Bookings changeOtherBooking(Long bookId, String checkInDate, String checkOutDate, HttpServletRequest request) throws Exception { + Bookings oBooking = bookingDao.findById(bookId).orElse(null); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + CfgOtherRoomStatus roomStatus = otherRoomStatusDao.findByStatusName("Pending Cancel"); + CfgOtherRoomStatus oRoomStatus = otherRoomStatusService.getOtherRoomStatusById(oBooking.getOtherRoomStatusId()); + String oStatus = oBooking.getLastOperaStatus(); + SysLogBooking logBooking = new SysLogBooking(); + Date now = new Date(); + LoginUserInfo userInfo = SysCommon.parseUserFromToken(request); + + // 将String转换为Date + Date checkIn = dateFormat.parse(checkInDate); + Date checkOut = dateFormat.parse(checkOutDate); + oBooking.setChangeCheckinDate(checkInDate); + oBooking.setChangeCheckoutDate(checkOutDate); + oBooking.setLastOperaStatus("Pending Cancel"); + oBooking.setOtherRoomStatusId(roomStatus.getId()); + oBooking.setOtherFollowUpStatusId(Long.valueOf("5")); + LogUtil.info(BookingController.class, + "[changeBookingDate] Start Change Other Booking BookingId = " + oBooking.getId()); + bookingDao.save(oBooking); +// 写入Audit Trail + logBooking.setOccurTime(now); + logBooking.setBookId(oBooking.getId()); + logBooking.setEventCode("Status"); + logBooking.setChangeFrom(oStatus); + logBooking.setChangeTo("Pending Cancel(CHANGE DATE)"); + logBooking.setLoginId(userInfo.getLoginId()); + logBooking.setLoginName(userInfo.getLoginId()); + sysLogBookingService.save(logBooking); + otherBookingService.processOtherAllotment(oBooking.getRoomId(), checkOut, + checkIn, oBooking.getPropertyId(), oBooking.getSegmentId()); + return oBooking; + } + + private BookingsView getEmailInfo(BookingsView bookView, String userId) { + if (bookView != null) { + JSONArray dynList = !StringUtils.isEmpty(bookView.getSharer()) && !Strings.CS.equals("[]", bookView.getSharer()) ? + JSONArray.parseArray(bookView.getSharer()) : new JSONArray(); + String sharerString = ""; + if (!dynList.isEmpty()) { + for (int a = 0; a < dynList.size(); a++) { + Gson gson = new Gson(); + JSONObject shareObj = (JSONObject) dynList.get(a); + String sharePlayerId = shareObj.getString("playerId"); + String shareName = shareObj.getString("name"); + LogUtil.info(BookingService.class, + "[editBooking] sharePlayerId " + gson.toJson(sharePlayerId)); + LogUtil.info(BookingService.class, + "[editBooking] shareName " + gson.toJson(shareName)); + if (!StringUtils.isEmpty(sharePlayerId)) { + sharerString += (sharePlayerId + " " + shareName) + " "; + } else if (!StringUtils.isEmpty(shareName)) { + sharerString += (shareName) + " "; + } else { + continue; + } + } + } + bookView.setSharerName(sharerString); + String playerId = bookView.getPlayerId() != null ? bookView.getPlayerId() : null; + BaseApiResponse findWebPlayerResult = playerService.findWebPlayerProfileByPlayerId(playerId); + if (findWebPlayerResult.isSuccess()) { + try { + PlayerProfileEntry profile = findWebPlayerResult.getData(); + bookView.setMemberTier(profile.getTierName()); + bookView.setMemberLastName(profile.getName()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + } + return bookView; + } + + // 判断时间是否超过viewYesterday Range + private boolean isPassTimeNow() { + boolean isPass = false; + CfgSettings cancelStart = settingService.getSettingByKey("OTHERBOOKING_CANCEL_START"); + CfgSettings cancelEnd = settingService.getSettingByKey("OTHERBOOKING_CANCEL_END"); + int startMinute = Integer.parseInt(cancelStart.getKeyValues().split(":")[0]) * 60 + + Integer.parseInt(cancelStart.getKeyValues().split(":")[1]); + int endMinute = Integer.parseInt(cancelEnd.getKeyValues().split(":")[0]) * 60 + + Integer.parseInt(cancelEnd.getKeyValues().split(":")[1]); +// 获跟当就的日期和时间 + LocalDateTime currentDateTime = LocalDateTime.now(); + int currentMinute = currentDateTime.getMinute() + currentDateTime.getHour() * 60; + if (currentMinute > startMinute && currentMinute < endMinute) { + isPass = true; + } + return isPass; + } + +} + diff --git a/src/main/resources/AuthKey_79FNU7K4J9_Development.p8 b/src/main/resources/AuthKey_79FNU7K4J9_Development.p8 new file mode 100644 index 0000000..08d3b84 --- /dev/null +++ b/src/main/resources/AuthKey_79FNU7K4J9_Development.p8 @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgfQ1bQlwCYsPyrRua +2OB2VRxxlA2/3PUFWuS/+/3P1RygCgYIKoZIzj0DAQehRANCAASn2hmu3BJ02OmZ +hNS/y6SwiIJi4tWQB1lxX0EksfsRgU1e3pp9gcMeIvY8gQA44QQJSvV7JWIu2fMj +1b9xpZU/ +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 0000000..fe8f3d8 --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,161 @@ +spring: + datasource: + mgm: + driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver + jdbc-url: jdbc:sqlserver://47.238.46.81:1433;databasename=db_mgm_mcrm_daylight;encrypt=false;trustServerCertificate=false;hostNameInCertificate=*;loginTimeout=30 + username: sa + password: 666888@Welcomewilltech + continue-on-error: true + hikari: + minimum-idle: 10 + maximum-pool-size: 50 + idle-timeout: 600000 + connection-timeout: 600000 + max-lifetime: 1800000 + + opera: + driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver + jdbc-url: jdbc:sqlserver://47.238.46.81:1433;databasename=db_mgm_mcrm_daylight;encrypt=false;trustServerCertificate=false;hostNameInCertificate=*;loginTimeout=30 + username: sa + password: 666888@Welcomewilltech + continue-on-error: true + hikari: + minimum-idle: 10 + maximum-pool-size: 50 + idle-timeout: 600000 + connection-timeout: 600000 + max-lifetime: 1800000 + + jpa: + show-sql: false + properties: + hibernate: + format_sql: true + + http: + encoding: + force: true + charset: UTF-8 + enabled: true + + messages: + basename: i18n/messages + + thymeleaf: + suffix: .shtml + cache: false + + devtools: + restart: + enabled: false + + activemq: + broker-url: tcp://localhost:61616 + user: admin + password: admin + concurrency: 2-10 + + jms: + pub-sub-domain: false + + security: + enabled: false + oauth2: + client: + registration: + adfs: + register-id: MCRM_OAUTH + client-id: 0fa96b30-f429-474e-ace4-34a82b816682 + client-secret: L_7tIOfEL9iJlksST9L9dOPkUR5KHU405SMAAsNU + redirect-uri: https://mcrm.willtechmacau.com:9086/sso_callback/login + provider: + adfs: + token-uri: https://adserver.willtechmacau.com/adfs/oauth2/token + +server: + port: 9086 + tomcat: + uri-encoding: UTF-8 + ssl: + key-store: classpath:mcrm.willtechmacau.com.pfx + key-store-password: o6gxpp51 + key-store-type: PKCS12 + +logging: + config: classpath:logback.xml +springdoc: + swagger-ui: + path: /swagger-ui.html + operations-sorter: alpha + tags-sorter: alpha + doc-expansion: none + api-docs: + path: /v3/api-docs + default-consumes-media-type: application/json + default-produces-media-type: application/json + +app_ctrl_topic: cms_app_control +book_ctrl_queue: booking_control + +adfs: + hostname: https://adserver.willtechmacau.com + +mcrm: + security: + jwt: + secret-key: SecretKeyWhichShouldBeLongEnoughToBeSecure67848563 + api-token-expiration: 5 + mobile-session-expiration: 30 + + daylight-system-id: 3a151ad3-46be-4644-b656-71d3b037b309 + +#============== Daylight Service =================== +daylight: + url: http://localhost:9087/api/daylight/proxy + +sso: + callback: + login: + success: https://mcrm.willtechmacau.com:9086/sso_callback/login + logout: + success: https://mcrm.willtechmacau.com:9086/sso_callback/logout + +relying_party: MCRM_APP +ad_domain: willtechmacau.com +adfs_domain: adserver.willtechmacau.com +adfs_secret_key: uBdUx82vPHkDKb284d7NkjFoNcKWBuka +host_name: mcrm +adfs_request_timeout: 10000 +adfs_login_timeout: 60000 + +allow_origin: "http://localhost:5173,http://127.0.0.1:5173,http://localhost:8080,MGM_CRM_APP,MGM_CRM_CMS,https://localhost:9085,http://localhost:8081,http://127.0.0.1:8081,https://localhost:9087/api/esb/proxy" +soap_servers: "http://localhost:5173,http://127.0.0.1:5173" +http_api_servers: "http://localhost:5173,http://127.0.0.1:5173,http://localhost:9087" +allow_ip: "0:0:0:0:0:0:0:1,127.0.0.1" +internal_network_pattern: 127.0.0.1;0:0:0:0;10.*.*.*;192.168.*.*;172.16.*.*;172.17.*.*;172.18.*.*;172.19.*.*;172.20.*.*;172.31.*.* + +#============== HttpClient 配置 =================== +httpclient: + pool: + max-total: 100 # 连接池最大连接数 + max-per-route: 10 # 每个路由最大连接数 + timeout: + connection-request: 5 # 连接请求超时时间(秒) + response: 10 # 响应超时时间(秒) + redirects-enabled: false # 是否启用重定向 + +apns: + team-id: YXJ2H36G5R + key-id: 79FNU7K4J9 + bundle-id: com.mgm.crmhostroombookingdaylightdevelopment + key-file: /AuthKey_79FNU7K4J9_Development.p8 + proxy: + enabled: false + host: + port: 0 + username: + password: + # Dev host + host: api.sandbox.push.apple.com + # Production Host +# host: api.push.apple.com \ No newline at end of file diff --git a/src/main/resources/application-dev2.yml b/src/main/resources/application-dev2.yml new file mode 100644 index 0000000..e1b626e --- /dev/null +++ b/src/main/resources/application-dev2.yml @@ -0,0 +1,131 @@ +spring: + datasource: + mgm: + driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver + jdbc-url: jdbc:sqlserver://47.238.46.81:1433;databasename=db_mgm_mcrm_daylight;encrypt=false;trustServerCertificate=false;hostNameInCertificate=*;loginTimeout=30 + username: sa + password: 666888@Welcomewilltech + continue-on-error: true + hikari: + minimum-idle: 10 + maximum-pool-size: 50 + idle-timeout: 600000 + connection-timeout: 600000 + max-lifetime: 1800000 + opera: + driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver + jdbc-url: jdbc:sqlserver://47.238.46.81:1433;databasename=db_mgm_mcrm_daylight;encrypt=false;trustServerCertificate=false;hostNameInCertificate=*;loginTimeout=30 + username: sa + password: 666888@Welcomewilltech + continue-on-error: true + hikari: + minimum-idle: 10 + maximum-pool-size: 50 + idle-timeout: 600000 + connection-timeout: 600000 + max-lifetime: 1800000 + + jpa: + mgm: + show-sql: false + properties: + hibernate: + format_sql: true + proc: + param_null_passing: true + opera: + show-sql: false + properties: + hibernate: + format_sql: true + proc: + param_null_passing: true + show-sql: false + properties: + hibernate: + format_sql: true + + devtools: + restart: + enabled: true + + messages: + basename: i18n/messages + + thymeleaf: + suffix: .shtml + cache: false + + activemq: + broker-url: tcp://localhost:61616 + user: admin + password: admin + concurrency: 2-10 + jms: + pub-sub-domain: false + security: + enable: false + oauth2: + client: + registration: + adfs: + register-id: MCRM_OAUTH + client-id: 0fa96b30-f429-474e-ace4-34a82b816682 + client-secret: L_7tIOfEL9iJlksST9L9dOPkUR5KHU405SMAAsNU + redirect-uri: https://mcrm.willtechmacau.com:9086/sso_callback/login + provider: + adfs: + token-uri: https://adserver.willtechmacau.com/adfs/oauth2/token + + +app_ctrl_topic: cms_app_control +book_ctrl_queue: booking_control + +server: + port: 9086 + tomcat: + uri-encoding: UTF-8 + servlet: + encoding: + force: true + charset: UTF-8 + enabled: true + ssl: + key-store: classpath:mcrm.willtechmacau.com.pfx + key-store-password: o6gxpp51 + key-store-type: PKCS12 + +logging: + config: classpath:logback.xml + +#============== App Configuration =============== +mcrm: + security: + jwt: + secret-key: SecretKeyWhichShouldBeLongEnoughToBeSecure67848563 + api-token-expiration: 5 + mobile-session-expiration: 30 + +adfs: + hostname: https://adserver.willtechmacau.com + +sso: + callback: + login: + success: https://mcrm.willtechmacau.com:9086/sso_callback/login + logout: + success: https://mcrm.willtechmacau.com:9086/sso_callback/logout + +relying_party: MCRM_APP +ad_domain: willtechmacau.com +adfs_domain: adserver.willtechmacau.com +adfs_secret_key: uBdUx82vPHkDKb284d7NkjFoNcKWBuka +host_name: mcrm +adfs_request_timeout: 10000 +adfs_login_timeout: 60000 + +allow_origin: http://localhost:5173,http://127.0.0.1:5173,http://localhost:8080,MGM_CRM_APP,MGM_CRM_CMS,https://localhost:9085,http://localhost:8081,http://127.0.0.1:8081 +soap_servers: http://localhost:5173,http://127.0.0.1:5173 +http_api_servers: http://localhost:5173,http://127.0.0.1:5173 +allow_ip: 0:0:0:0:0:0:0:1 +internal_network_pattern: 127.0.0.1;0:0:0:0;10.*.*.*;192.168.*.*;172.16.*.*;172.17.*.*;172.18.*.*;172.19.*.*;172.20.*.*;172.31.*.* diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..caf4dfc --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,3 @@ +spring: + profiles: + active: dev \ No newline at end of file diff --git a/src/main/resources/i18n/messages.properties b/src/main/resources/i18n/messages.properties new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/i18n/messages_en_US.properties b/src/main/resources/i18n/messages_en_US.properties new file mode 100644 index 0000000..bb655c6 --- /dev/null +++ b/src/main/resources/i18n/messages_en_US.properties @@ -0,0 +1,26 @@ +gamecenter.title=Game List +gamecenter.welcome=Welcome, +gamecenter.will_text=CARD NO.: +gamecenter.button.back=BACK +gamecenter.gamechance=Game Chance(s): + +common.error_message.error_code_200=OK +common.error_message.error_code_401=Authorization failed +common.error_message.error_code_422=Parameter error +common.error_message.error_code_301=Game is unavailable +common.error_message.error_code_302=Game chance has been exhausted +common.error_message.error_code_303=Error result return +common.error_message.error_code_304=Data duplicated +common.error_message.error_code_305=Invalid request +common.error_message.error_code_306=Session timeout, please login and re-enter game +common.error_message.error_code_307=Reward exhausted, game is finished +common.error_message.error_code_701=Request error +common.error_message.error_code_308=Game Session Timeout +common.error_message.error_code_309=No Customer Tier +common.error_message.error_code_310=Game is finished, gamechance returned + +common.no_game_chance=Game chance has been exhausted +common.get_game_chance_error=Get game chance error +common.get_game_chance_request_error=Get game chance request error +common.no_game_available=No Game Available +common.game_session_timeout=Session timeout \ No newline at end of file diff --git a/src/main/resources/i18n/messages_zh_CN.properties b/src/main/resources/i18n/messages_zh_CN.properties new file mode 100644 index 0000000..198a24e --- /dev/null +++ b/src/main/resources/i18n/messages_zh_CN.properties @@ -0,0 +1,26 @@ +gamecenter.title=\u6e38\u620f\u4e2d\u5fc3 +gamecenter.welcome=\u6b22\u8fce, +gamecenter.will_text=\u5361\u53f7: +gamecenter.button.back=\u8fd4\u56de +gamecenter.gamechance=\u6e38\u620f\u673a\u4f1a: + +common.error_message.error_code_200=\u6210\u529f +common.error_message.error_code_401=\u8bf7\u6c42\u5b89\u5168\u9a8c\u8bc1\u5931\u8d25 +common.error_message.error_code_422=\u53c2\u6570\u9519\u8bef +common.error_message.error_code_301=\u6e38\u620f\u672a\u5f00\u653e +common.error_message.error_code_302=\u6e38\u620f\u6b21\u6570\u5df2\u7528\u5b8c +common.error_message.error_code_303=\u9519\u8bef\u7684\u8fd4\u56de\u7ed3\u679c +common.error_message.error_code_304=\u6570\u636e\u91cd\u590d +common.error_message.error_code_305=\u975e\u6cd5\u8bf7\u6c42 +common.error_message.error_code_306=\u6e38\u620f\u8d85\u65f6, \u8bf7\u91cd\u65b0\u8fdb\u5165 +common.error_message.error_code_307=\u5956\u9879\u5df2\u6d3e\u53d1\u5b8c\uff0c\u6e38\u620f\u5df2\u7ed3\u675f +common.error_message.error_code_701=\u8bf7\u6c42\u5931\u8d25 +common.error_message.error_code_308=\u6e38\u620f\u8d85\u65f6, \u8bf7\u91cd\u65b0\u8fdb\u5165 +common.error_message.error_code_309=\u7372\u53d6\u6703\u54e1\u7b49\u7d1a\u5931\u6557 +common.error_message.error_code_310=\u6e38\u620f\u5df2\u7ed3\u675f, \u4e0d\u4f1a\u6263\u9664\u6e38\u620f\u673a\u4f1a + +common.no_game_chance=\u6e38\u620f\u6b21\u6570\u5df2\u7528\u5b8c +common.get_game_chance_error=\u83b7\u53d6\u6e38\u620f\u6b21\u6570\u9519\u8bef +common.get_game_chance_request_error=\u83b7\u53d6\u6e38\u620f\u6b21\u6570\u8bf7\u6c42\u9519\u8bef +common.no_game_available=\u6ca1\u6709\u53ef\u53c2\u4e0e\u7684\u6e38\u620f +common.game_session_timeout=\u6e38\u620f\u8d85\u65f6 \ No newline at end of file diff --git a/src/main/resources/i18n/messages_zh_TW.properties b/src/main/resources/i18n/messages_zh_TW.properties new file mode 100644 index 0000000..dd24883 --- /dev/null +++ b/src/main/resources/i18n/messages_zh_TW.properties @@ -0,0 +1,26 @@ +gamecenter.title=\u904a\u6232\u4e2d\u5fc3 +gamecenter.welcome=\u6b61\u8fce, +gamecenter.will_text=\u5361\u865f: +gamecenter.button.back=\u8fd4\u56de +gamecenter.gamechance=\u904a\u6232\u6a5f\u6703: + +common.error_message.error_code_200=\u6210\u529f +common.error_message.error_code_401=\u8acb\u6c42\u5b89\u5168\u9a57\u8b49\u5931\u6557 +common.error_message.error_code_422=\u53c3\u6578\u932f\u8aa4 +common.error_message.error_code_301=\u904a\u6232\u672a\u958b\u653e +common.error_message.error_code_302=\u904a\u6232\u6b21\u6578\u5df2\u7528\u5b8c +common.error_message.error_code_303=\u932f\u8aa4\u7684\u8fd4\u56de\u7d50\u679c +common.error_message.error_code_304=\u6578\u64da\u91cd\u8907 +common.error_message.error_code_305=\u975e\u6cd5\u8acb\u6c42 +common.error_message.error_code_306=\u904a\u6232\u8d85\u6642\uff0c\u8acb\u91cd\u65b0\u9032\u5165 +common.error_message.error_code_307=\u5956\u52b1\u5df2\u6d3e\u767c\u5b8c\uff0c\u904a\u6232\u5df2\u7d50\u675f +common.error_message.error_code_701=\u8acb\u6c42\u932f\u8aa4 +common.error_message.error_code_308=\u904a\u620f\u8d85\u65f6, \u8bf7\u91cd\u65b0\u8fdb\u5165 +common.error_message.error_code_309=\u7372\u53d6\u6703\u54e1\u7b49\u7d1a\u5931\u6557 +common.error_message.error_code_310=\u904a\u6232\u5df2\u7d50\u675f, \u4e0d\u6703\u6263\u9664\u904a\u6232\u6a5f\u6703 + +common.no_game_chance=\u904a\u6232\u6b21\u6578\u5df2\u7528\u5b8c +common.get_game_chance_error=\u7372\u53d6\u904a\u6232\u6b21\u6578\u932f\u8aa4 +common.get_game_chance_request_error=\u7372\u53d6\u904a\u6232\u6b21\u6578\u8acb\u6c42\u932f\u8aa4 +common.no_game_available=\u6c92\u6709\u53ef\u53c3\u8207\u7684\u904a\u6232 +common.game_session_timeout=\u904a\u6232\u8d85\u6642 \ No newline at end of file diff --git a/src/main/resources/idp-metadata.xml b/src/main/resources/idp-metadata.xml new file mode 100644 index 0000000..577c6f2 --- /dev/null +++ b/src/main/resources/idp-metadata.xml @@ -0,0 +1 @@ +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电子邮件地址用户的电子邮件地址名用户的名名称用户的唯一名称UPN用户的用户主体名称(UPN)公用名用户的公用名AD FS 1.x 电子邮件地址与 AD FS 1.1 或 AD FS 1.0 互操作时用户的电子邮件地址组用户是其成员的组AD FS 1.x UPN与 AD FS 1.1 或 AD FS 1.0 互操作时用户的 UPN角色用户所具有的角色Surname用户的姓氏PPID用户的专用标识符名称 ID用户的 SAML 名称标识符身份验证时间戳用于显示验证用户身份的时间和日期身份验证方法用于验证用户身份的方法“仅拒绝”组 SID用户的“仅拒绝”组 SID“仅拒绝”主 SID用户的“仅拒绝”主 SID“仅拒绝”主组 SID用户的“仅拒绝”主组 SID组 SID用户的组 SID主组 SID用户的主组 SID主 SID用户的主 SIDWindows 帐户名用户的域帐户名(域\用户形式)为注册用户为了使用此设备,用户已注册设备标识符设备的标识符Device Registration 标识符Device Registration 的标识符Device Registration 显示名称Device Registration 的显示名称设备 OS 类型设备的 OS 类型设备 OS 版本设备的 OS 版本为托管设备设备由管理服务进行管理转发的客户端 IP用户的 IP 地址客户端应用程序客户端应用程序的类型客户端用户代理客户端访问应用程序所使用的设备类型客户端 IP客户端的 IP 地址终结点路径可用于确定主动和被动客户端的绝对终结点路径代理传递请求的联合服务器代理的 DNS 名称应用程序标识符信赖方标识符应用程序策略证书的应用程序策略授权密钥标识符对已颁发证书签名的证书授权密钥标识符扩展基本约束证书的基本约束之一增强密钥用法描述证书的增强密钥用法之一颁发者颁发 X.509 证书的证书颁发机构的名称颁发者名称证书颁发者的可分辨名称密钥用法证书的密钥用法之一不晚于以本地时间表示的证书有效截止日期不早于以本地时间表示的证书生效日期证书策略颁发证书所依据的策略公钥证书的公钥证书原始数据证书的原始数据使用者可选名称证书的备用名称之一序列号证书的序列号签名算法用于创建证书签名的算法使用者证书中的使用者使用者密钥标识符描述证书的使用者密钥标识符使用者名称证书中的使用者可分辨名称V2 模板名称颁发或续订证书时使用的版本 2 证书模板的名称。扩展名特定于 Microsoft。V1 模板名称颁发或续订证书时使用的版本 1 证书模板的名称。扩展名特定于 Microsoft。指纹证书的指纹X.509 版本证书的 X.509 格式版本在公司网络内部用于指明请求是否从公司网络中发出。密码到期时间用于显示密码到期时间密码到期天数用于显示距密码到期的天数更新密码 URL用于显示更新密码服务的 Web 地址身份验证方法引用用于指示用来验证用户的所有身份验证方法客户端请求 ID用户会话的标识符
https://adserver.willtechmacau.com/adfs/services/trust/2005/issuedtokenmixedasymmetricbasic256
https://adserver.willtechmacau.com/adfs/services/trust/2005/issuedtokenmixedsymmetricbasic256
https://adserver.willtechmacau.com/adfs/services/trust/13/issuedtokenmixedasymmetricbasic256
https://adserver.willtechmacau.com/adfs/services/trust/13/issuedtokenmixedsymmetricbasic256
https://adserver.willtechmacau.com/adfs/ls/
http://adserver.willtechmacau.com/adfs/services/trust
https://adserver.willtechmacau.com/adfs/services/trust/2005/issuedtokenmixedasymmetricbasic256
https://adserver.willtechmacau.com/adfs/ls/
MIIC8DCCAdigAwIBAgIQMzdxsgcsk7JBQOiD4S7Z9TANBgkqhkiG9w0BAQsFADA0MTIwMAYDVQQDEylBREZTIFNpZ25pbmcgLSBhZHNlcnZlci53aWxsdGVjaG1hY2F1LmNvbTAeFw0yNDA5MTYwODExMzNaFw0yNTA5MTYwODExMzNaMDQxMjAwBgNVBAMTKUFERlMgU2lnbmluZyAtIGFkc2VydmVyLndpbGx0ZWNobWFjYXUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7IYsJuA7nu7lEreZbWUuZbW4ywfm6rGddTYRusRSrqJRmcLtIby9FQP3jt5brPzoleSbVsrOU+3h9IXMkfJ1sBu+BcW1X/IzUIrQsjJQss1L/9b81ZMiy+ew1QTg2CZt8fQbbt+PXh8jm3vFvSQdXHMD/cO16eZNGBZFeq8xM15k7bo+aAm6X0XQbIOsAhymAFwVLLpEzXxsmCAIy6hz9cdVH1GOVoKtX7SGw6uDGiwrZLNHJsRVzt0Byx3xvFXM1zEZBRJ0nexWK6zk+80AuLoZqiidwi8cnsdceBk4no5b4COE8bEFMN8oR6/ohDW6JQBhVIJS+jwJCweez9xcgQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBoRtn4mw9VUCKe2Bg+XskP/rAPPMsuENH26S6100vEvJu35z/ak61ttCuF3d7lpI/WVge/AZNbulx3Hl0EzCx4tN3cnVU5aW/0Ynn4My5m8Lz+cK37crukTtFqY2rdBlSAUy1uw+z9OXluJ/St7DL7cbLNyJg/ncKRncjkb0rtbFQ3kOiULO3WTWDQcKbQjFZKYpJ+QmTq2DmGkuYb+lwxcK+ObBm3gklw77f3Fhz5Briz9UEPVzp5QeLpfeNEbI4rvwSeUo/UQ4eyE2Ux4K5LNvXDSHTBiggUl9yTXLjvPdT439HRuiFpZ+fj19lB4Ywu8dphvkfJO12FEQpaNqO/电子邮件地址用户的电子邮件地址名用户的名名称用户的唯一名称UPN用户的用户主体名称(UPN)公用名用户的公用名AD FS 1.x 电子邮件地址与 AD FS 1.1 或 AD FS 1.0 互操作时用户的电子邮件地址组用户是其成员的组AD FS 1.x UPN与 AD FS 1.1 或 AD FS 1.0 互操作时用户的 UPN角色用户所具有的角色Surname用户的姓氏PPID用户的专用标识符名称 ID用户的 SAML 名称标识符身份验证时间戳用于显示验证用户身份的时间和日期身份验证方法用于验证用户身份的方法“仅拒绝”组 SID用户的“仅拒绝”组 SID“仅拒绝”主 SID用户的“仅拒绝”主 SID“仅拒绝”主组 SID用户的“仅拒绝”主组 SID组 SID用户的组 SID主组 SID用户的主组 SID主 SID用户的主 SIDWindows 帐户名用户的域帐户名(域\用户形式)为注册用户为了使用此设备,用户已注册设备标识符设备的标识符Device Registration 标识符Device Registration 的标识符Device Registration 显示名称Device Registration 的显示名称设备 OS 类型设备的 OS 类型设备 OS 版本设备的 OS 版本为托管设备设备由管理服务进行管理转发的客户端 IP用户的 IP 地址客户端应用程序客户端应用程序的类型客户端用户代理客户端访问应用程序所使用的设备类型客户端 IP客户端的 IP 地址终结点路径可用于确定主动和被动客户端的绝对终结点路径代理传递请求的联合服务器代理的 DNS 名称应用程序标识符信赖方标识符应用程序策略证书的应用程序策略授权密钥标识符对已颁发证书签名的证书授权密钥标识符扩展基本约束证书的基本约束之一增强密钥用法描述证书的增强密钥用法之一颁发者颁发 X.509 证书的证书颁发机构的名称颁发者名称证书颁发者的可分辨名称密钥用法证书的密钥用法之一不晚于以本地时间表示的证书有效截止日期不早于以本地时间表示的证书生效日期证书策略颁发证书所依据的策略公钥证书的公钥证书原始数据证书的原始数据使用者可选名称证书的备用名称之一序列号证书的序列号签名算法用于创建证书签名的算法使用者证书中的使用者使用者密钥标识符描述证书的使用者密钥标识符使用者名称证书中的使用者可分辨名称V2 模板名称颁发或续订证书时使用的版本 2 证书模板的名称。扩展名特定于 Microsoft。V1 模板名称颁发或续订证书时使用的版本 1 证书模板的名称。扩展名特定于 Microsoft。指纹证书的指纹X.509 版本证书的 X.509 格式版本在公司网络内部用于指明请求是否从公司网络中发出。密码到期时间用于显示密码到期时间密码到期天数用于显示距密码到期的天数更新密码 URL用于显示更新密码服务的 Web 地址身份验证方法引用用于指示用来验证用户的所有身份验证方法客户端请求 ID用户会话的标识符
https://adserver.willtechmacau.com/adfs/services/trust/2005/certificatemixed
https://adserver.willtechmacau.com/adfs/services/trust/mex
https://adserver.willtechmacau.com/adfs/ls/
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:oasis:names:tc:SAML:1.1:nameid-format:emailAddressurn:oasis:names:tc:SAML:2.0:nameid-format:persistenturn:oasis:names:tc:SAML:2.0:nameid-format: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:oasis:names:tc:SAML:1.1:nameid-format:emailAddressurn:oasis:names:tc:SAML:2.0:nameid-format:persistenturn:oasis:names:tc:SAML:2.0:nameid-format:transient
\ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..3545290 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%-5level] %logger{50} - %msg%n + + + + + + + ${LOG_APP_HOME}/base.%d{yyyy-MM-dd}.log + + + ${LOG_MAX_HISTORY} + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{500} - %msg%n + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/mcrm.willtechmacau.com.pfx b/src/main/resources/mcrm.willtechmacau.com.pfx new file mode 100644 index 0000000000000000000000000000000000000000..8b48f703ac77a3d61a69f35bf2858254a46a70d0 GIT binary patch literal 4653 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 N8R!{8D|H>B{tuavN{;{l literal 0 HcmV?d00001 diff --git a/src/main/resources/static/WP.png b/src/main/resources/static/WP.png new file mode 100644 index 0000000000000000000000000000000000000000..dfc32bad90c0293423a0ead2aa0f64c569b7f8fc GIT binary patch literal 10052 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

#%-V4(arr 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 + + + + +Insert title here + + +SAML2 Login +

+ username:
+ password:
+ Relying Party:
+ + +
+ Relying Party:
+ Logout Callback:
+ +
+ + \ No newline at end of file diff --git a/src/test/java/com/mgm/daylight/EnumBookingStatusTest.java b/src/test/java/com/mgm/daylight/EnumBookingStatusTest.java new file mode 100644 index 0000000..903095b --- /dev/null +++ b/src/test/java/com/mgm/daylight/EnumBookingStatusTest.java @@ -0,0 +1,21 @@ +package com.mgm.daylight; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import org.hibernate.collection.spi.PersistentBag; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +class EnumBookingStatusTest { + + @Test + void test() { + String a = "{\"birthday\":\"2000-01-01\",\"chineseName\":\"劉明浩\",\"codedFlag\":1,\"country\":\"CN\",\"englishName\":\"IVAN LAU\",\"language\":\"E\",\"name\":\"IVAN LAU\",\"nameIds\":[710825],\"passport\":\"123456\",\"phoneType\":\"MOBILE\",\"playerId\":\"11010001\",\"playerPhone\":\"123456\",\"salutation\":\"Mr.\",\"state\":\"MO\",\"statusCode\":\"OK\",\"statusDescription\":\"SUCCESS\",\"tierId\":\"34\",\"tierName\":\"SUPREME 88\",\"userId\":\"\"}"; + + JSONObject bookingJson = JSON.parseObject(a); + + System.out.println(bookingJson.toJSONString()); + } +} diff --git a/src/test/java/com/mgm/daylight/HttpEntityBuilderTest.java b/src/test/java/com/mgm/daylight/HttpEntityBuilderTest.java new file mode 100644 index 0000000..c46b28b --- /dev/null +++ b/src/test/java/com/mgm/daylight/HttpEntityBuilderTest.java @@ -0,0 +1,29 @@ +package com.mgm.daylight; + +import com.mgm.mcrm.common.httpclient.HttpEntityBuilder; +import org.apache.hc.core5.http.NameValuePair; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class HttpEntityBuilderTest { + + + void checkHasParasKeepsDuplicateQueryNames() throws Exception { + List nvps = new ArrayList<>(); + + String url = HttpEntityBuilder.checkHasParas( + "/api-gateway/booking/v1/reservations?pageNumber=1&pageSize=500" + + "&extend=PurchaseElements&extend=Account&extend=CustomFields", + nvps, + "utf-8"); + + assertEquals("/api-gateway/booking/v1/reservations", url); + assertEquals("PurchaseElements", nvps.get(2).getValue()); + assertEquals("Account", nvps.get(3).getValue()); + assertEquals("CustomFields", nvps.get(4).getValue()); + } +} diff --git a/src/test/java/com/mgm/daylight/SmallTest.java b/src/test/java/com/mgm/daylight/SmallTest.java new file mode 100644 index 0000000..23e79d7 --- /dev/null +++ b/src/test/java/com/mgm/daylight/SmallTest.java @@ -0,0 +1,19 @@ +package com.mgm.daylight; + + +import com.mgm.mcrm.CRMMobileApplication; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest(classes = {CRMMobileApplication.class}) +class SmallTest { + + @Value("${mcrm.daylight-system-id}") + private String daylightSystemId; + +// @Test + void checkTest() { + System.out.println(daylightSystemId); + } +} diff --git a/src/test/java/com/mgm/mcrm/booking/controllers/BookingControllerRecordSearchTest.java b/src/test/java/com/mgm/mcrm/booking/controllers/BookingControllerRecordSearchTest.java new file mode 100644 index 0000000..28d3ae5 --- /dev/null +++ b/src/test/java/com/mgm/mcrm/booking/controllers/BookingControllerRecordSearchTest.java @@ -0,0 +1,76 @@ +package com.mgm.mcrm.booking.controllers; + +import com.mgm.mcrm.appsetting.models.CfgSettings; +import com.mgm.mcrm.appsetting.services.SettingService; +import com.mgm.mcrm.appsetting.services.SysSettingService; +import com.mgm.mcrm.authorization.dtos.LoginUserInfo; +import com.mgm.mcrm.basesetting.daylight.dtos.response.ProfileDetailResponse; +import com.mgm.mcrm.basesetting.daylight.services.DaylightService; +import com.mgm.mcrm.booking.dtos.BookingDto; +import com.mgm.mcrm.booking.dtos.search.BookingSearchRequest; +import com.mgm.mcrm.booking.services.BookingService; +import com.mgm.mcrm.booking.services.NonMGMBookingService; +import com.mgm.mcrm.booking.services.OperaDBBookingService; +import com.mgm.mcrm.booking.services.WaitlistBookingService; +import com.mgm.mcrm.booking.services.mockup.BookingServiceMockup; +import com.mgm.mcrm.common.constants.SysConstants; +import com.mgm.mcrm.common.dtos.BaseApiResponse; +import com.mgm.mcrm.common.dtos.mgm_api.PlayerProfileEntry; +import com.mgm.mcrm.player.services.PlayerService; +import org.junit.jupiter.api.Test; +import org.springframework.test.util.ReflectionTestUtils; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class BookingControllerRecordSearchTest { + + @Test + void filterAndSortBookingResultKeepsPendingVersionWhenSameBookingAppearsTwice() throws Exception { + BookingController controller = new BookingController(); + SettingService settingService = mock(SettingService.class); + ReflectionTestUtils.setField(controller, "settingService", settingService); + + CfgSettings cutoffStart = new CfgSettings(); + cutoffStart.setKeyValues("00:00"); + CfgSettings cutoffEnd = new CfgSettings(); + cutoffEnd.setKeyValues("23:59"); + when(settingService.getSettingByKey("VIEW_YESTERDAY_TODOLIST_START")).thenReturn(cutoffStart); + when(settingService.getSettingByKey("VIEW_YESTERDAY_TODOLIST_END")).thenReturn(cutoffEnd); + + Date futureCheckin = new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000); + Date futureCheckout = new Date(System.currentTimeMillis() + 2 * 24 * 60 * 60 * 1000); + + BookingDto daylightMergedVersion = new BookingDto(); + daylightMergedVersion.setId(100L); + daylightMergedVersion.setConfirmationNo("DL100"); + daylightMergedVersion.setApproveStatus("N"); + daylightMergedVersion.setCheckinDate(futureCheckin); + daylightMergedVersion.setCheckoutDate(futureCheckout); + + BookingDto pendingVersion = new BookingDto(); + pendingVersion.setId(100L); + pendingVersion.setConfirmationNo("DL100"); + pendingVersion.setApproveStatus("PN"); + pendingVersion.setCheckinDate(futureCheckin); + pendingVersion.setCheckoutDate(futureCheckout); + + List input = new ArrayList<>(); + input.add(daylightMergedVersion); + input.add(pendingVersion); + + Method filterMethod = BookingController.class.getDeclaredMethod("filterAndSortBookingResult", List.class); + filterMethod.setAccessible(true); + List result = (List) filterMethod.invoke(controller, input); + + assertEquals(1, result.size()); + } +}