Browse Source

Community Hall new changes code updation

master
KaNi-04 2 months ago
parent
commit
1d516f8e10
  1. 3
      .vscode/settings.json
  2. 2
      jwtToken.txt
  3. 25
      src/main/java/com/gcc/communityHall/controller/HeadquartersController.java
  4. 7
      src/main/java/com/gcc/communityHall/controller/UserAPIController.java
  5. 2
      src/main/java/com/gcc/communityHall/entity/BookingDetails.java
  6. 175
      src/main/java/com/gcc/communityHall/paymentService/controller/PaymentAPIController.java
  7. 98
      src/main/java/com/gcc/communityHall/paymentService/scheduler/PaymentStatusScheduler.java
  8. 6
      src/main/java/com/gcc/communityHall/repository/BookingDetailsRepository.java
  9. 8
      src/main/java/com/gcc/communityHall/repository/LoginRepository.java
  10. 9
      src/main/java/com/gcc/communityHall/service/BookingService.java
  11. 293
      src/main/java/com/gcc/communityHall/service/Impl/BookingServiceImpl.java
  12. 2
      src/main/java/com/gcc/communityHall/service/MailService.java
  13. 843
      src/main/resources/resources/templates/headquarters/sixmonthold-transactions.html
  14. 91
      src/main/resources/templates/admin/bookingwaiting.html
  15. 40
      src/main/resources/templates/fragments/PaymentScript.html
  16. 2
      src/main/resources/templates/fragments/headquartersMenu.html
  17. 91
      src/main/resources/templates/headquarters/bookingwaiting.html
  18. 4
      src/main/resources/templates/headquarters/reports.html
  19. 64
      src/main/resources/templates/headquarters/sixmonthold-transactions.html
  20. 18
      src/main/resources/templates/user/hallbookingform.html
  21. 155
      src/main/resources/templates/user/viewhistory.html
  22. 3530
      src/main/resources/templates/user/viewhistory_old.html
  23. 3538
      src/main/resources/templates/user/viewhistory_reschedulelogic.html

3
.vscode/settings.json

@ -1,3 +1,4 @@
{
"java.compile.nullAnalysis.mode": "automatic"
"java.compile.nullAnalysis.mode": "automatic",
"java.configuration.updateBuildConfiguration": "interactive"
}

2
jwtToken.txt

@ -1 +1 @@
eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyVHlwZSI6ImhlYWRxdWFydGVycyIsImhhbGxJZCI6MCwiaGFsbElkcyI6IiIsIm1vYmlsZU51bWJlciI6OTUxNzUzODUyNCwiem9uZSI6IjAwIiwiZXhwIjoxNzgzOTI4NDY4fQ.JDuWljfRXzemAjgmLj4MFq3DgmL9Z1hbE8_LoLpQQ0jLZp4wBbyvmEopk9BHmWtzh8SlDN6dxQHEJDsxTRt0_Q
eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyVHlwZSI6ImhlYWRxdWFydGVycyIsImhhbGxJZCI6MCwiaGFsbElkcyI6IiIsIm1vYmlsZU51bWJlciI6OTUxNzUzODUyNCwiem9uZSI6IjAwIiwiZXhwIjoxNzg1MzI4MDYwfQ.aXxOu_OHvSMRSKZFqyQzzi9rFw8KCuC5m-Hv4QNSk36_lWZCcZJSvbPHDyQKyELJkbZdURa9p0dd6sPmDoZsLg

25
src/main/java/com/gcc/communityHall/controller/HeadquartersController.java

@ -1177,11 +1177,6 @@ public class HeadquartersController {
return result;
}
/**
* Marks a booking as "mail sent":
* 1. Stamps mail_sent = 1, mail_sent_date = NOW() on booking_details.
* 2. Inserts a row into six_month_mail_log for audit history.
*/
@PostMapping("/sixmonthold-transactions/markMailSent")
@ResponseBody
@Transactional
@ -1206,7 +1201,7 @@ public class HeadquartersController {
String mailBody = mailService.sendRefundFollowupMail(
bookingId, bookingStatus, transactionId, tpslId, transactionDate, refundAmount);
// 2. Stamp booking_details: mail_sent = 1, mail_sent_date = NOW()
// 2. Update booking_details: mail_sent = 1, mail_sent_date = NOW()
bookingDetailsRepository.markMailSent(bookingId);
// 3. Write audit log entry
@ -1223,24 +1218,6 @@ public class HeadquartersController {
return response;
}
/**
* Update Refund Details for Mail Sent Bookings (new method – does NOT touch
* existing endpoints).
*
* ID logic:
* - Cancelled / Rejected → bookingId is the primary reference.
* - Approved → settlementId is the primary reference;
* bookingId used to fetch BookingDetails.
*
* Tables updated (in order):
* 1. booking_history – archive current BookingDetails snapshot.
* 2. booking_details – bookingStatus=COMPLETED, refundStatus=COMPLETED.
* 3. settlement_history – archive Settlement snapshot (APPROVED only).
* 4. settlement – update comments + updatedDate (APPROVED only).
* 5. refund_transaction – upsert.
* 6. refund_response – upsert with arn_number.
* 7. application_logs – audit entry.
*/
@PostMapping("/sixmonthold-transactions/updateRefundDetails")
@ResponseBody
@Transactional

7
src/main/java/com/gcc/communityHall/controller/UserAPIController.java

@ -1329,9 +1329,12 @@ public class UserAPIController {
public ResponseEntity<String> updateBookingDates(
@RequestParam int bookingId,
@RequestParam String startDate,
@RequestParam String endDate) {
@RequestParam String endDate,
@RequestParam(required = false, defaultValue = "0") int startingSlot,
@RequestParam(required = false, defaultValue = "0") int endingSlot) {
try {
Optional<String> updateResult = bookingService.updateBookingDatesAndCalendar(bookingId, startDate, endDate);
Optional<String> updateResult = bookingService.updateBookingDatesAndCalendar(
bookingId, startDate, endDate, startingSlot, endingSlot);
if (updateResult.isPresent()) {
if (updateResult.get().equals("Booking dates updated successfully.")) {
return new ResponseEntity<>(updateResult.get(), HttpStatus.OK);

2
src/main/java/com/gcc/communityHall/entity/BookingDetails.java

@ -5,6 +5,8 @@ import java.time.LocalDateTime;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.gcc.communityHall.paymentService.entity.RefundResponse;
import jakarta.persistence.*;
@Entity

175
src/main/java/com/gcc/communityHall/paymentService/controller/PaymentAPIController.java

@ -1,7 +1,8 @@
package com.gcc.communityHall.paymentService.controller;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Optional;
@ -17,6 +18,7 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gcc.communityHall.entity.BookingCalendar;
import com.gcc.communityHall.entity.BookingDetails;
import com.gcc.communityHall.entity.Users;
import com.gcc.communityHall.paymentService.DTO.Merchant;
@ -28,6 +30,7 @@ import com.gcc.communityHall.paymentService.entity.TransactionResponse;
import com.gcc.communityHall.paymentService.refund.DTO.TransactionRefundResponse;
import com.gcc.communityHall.paymentService.service.PaymentGatewayService;
import com.gcc.communityHall.paymentService.service.TransactionNumberGenerator;
import com.gcc.communityHall.repository.BookingCalendarRepository;
import com.gcc.communityHall.repository.BookingDetailsRepository;
import com.google.gson.Gson;
@ -35,12 +38,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
@Tag(
name = "CRUD REST APIs for Payment in CommunityHall",
description = "CRUD REST APIs in CommunityHall to CREATE, UPDATE, FETCH AND DELETE Booking details"
)
@Tag(name = "CRUD REST APIs for Payment in CommunityHall", description = "CRUD REST APIs in CommunityHall to CREATE, UPDATE, FETCH AND DELETE Booking details")
@RestController
@RequestMapping("/communityhall/payment/api")
@AllArgsConstructor
@ -57,17 +55,22 @@ public class PaymentAPIController {
private BookingDetailsRepository bookRepo;
@Autowired
private TransactionNumberGenerator transactionNumber;
private BookingCalendarRepository bookingCalendarRepository;
@Autowired
private TransactionNumberGenerator transactionNumber;
// @Operation(
// summary = "Refund the Total Amount REST API",
// description = "REST API to refunding the Total Amount if the admin will cancel and block the hall"
// description = "REST API to refunding the Total Amount if the admin will
// cancel and block the hall"
// )
// @GetMapping(value="/refund")
// public ResponseEntity<?> refundAmount(Model model,@RequestParam int bookingId) throws Exception {
// public ResponseEntity<?> refundAmount(Model model,@RequestParam int
// bookingId) throws Exception {
// //System.out.println("Refund Api call.......working on it");
// TransactionResponse transactionRes = this.paymentService.getTransactionResponseByBookingIdAndStatusCode(bookingId,this.paymentConfig.getTransactionSuccessCode());
// TransactionResponse transactionRes =
// this.paymentService.getTransactionResponseByBookingIdAndStatusCode(bookingId,this.paymentConfig.getTransactionSuccessCode());
// RefundResponse recordRefundResponse = new RefundResponse();
//
// Merchant merchant = new Merchant();
@ -93,20 +96,25 @@ public class PaymentAPIController {
//
// String encryptHxRefund = this.paymentService.encryptHxRefund(json);
// RestTemplate resttemplate = new RestTemplate();
// String Url ="https://www.tpsl-india.in/PaymentGateway/merchant2.pg/"+this.paymentConfig.getMerchantId();
// ResponseEntity<String> postForEntity = resttemplate.postForEntity(Url, encryptHxRefund, String.class);
// String Url
// ="https://www.tpsl-india.in/PaymentGateway/merchant2.pg/"+this.paymentConfig.getMerchantId();
// ResponseEntity<String> postForEntity = resttemplate.postForEntity(Url,
// encryptHxRefund, String.class);
//
// String decryptHxTRefund = this.paymentService.decryptHxTRefund(postForEntity.getBody());
// String decryptHxTRefund =
// this.paymentService.decryptHxTRefund(postForEntity.getBody());
// recordRefundResponse.setResponse(decryptHxTRefund);
// //recordRefundResponse.setUserId("2");//make it dynamic
// recordRefundResponse.setBookingId(bookingId);
// try {
// ObjectMapper objectMapper = new ObjectMapper();
//
// TransactionRefundResponse myObject = objectMapper.readValue(decryptHxTRefund, TransactionRefundResponse.class);
// TransactionRefundResponse myObject = objectMapper.readValue(decryptHxTRefund,
// TransactionRefundResponse.class);
// //System.out.println(myObject.toString());
//
// if(myObject.getPaymentMethod().getPaymentTransaction().getStatusCode().equals(this.paymentConfig.getRefundSuccessCode())) {
// if(myObject.getPaymentMethod().getPaymentTransaction().getStatusCode().equals(this.paymentConfig.getRefundSuccessCode()))
// {
// //System.out.println("Refund Process complete........"+bookingId);
// recordRefundResponse.setAmount(myObject.getPaymentMethod().getPaymentTransaction().getAmount());
// recordRefundResponse.setBalaceAmount(myObject.getPaymentMethod().getPaymentTransaction().getBalanceAmount());
@ -124,25 +132,107 @@ public class PaymentAPIController {
//
// }
@Operation(
summary = "payment-request REST API",
description = "REST API payment-request"
)
@Operation(summary = "payment-request REST API", description = "REST API payment-request")
@PostMapping(value = { "/payment-request" })
public HashMap<String, Object> startPayment(int userId, int bookingId) throws NoSuchAlgorithmException {
//System.out.println("I entered payment Service......"+bookingId+ "User Id :- "+userId);
// System.out.println("I entered payment Service......"+bookingId+ "User Id :-
// "+userId);
HashMap<String, Object> hs = new HashMap<>();
Optional<BookingDetails> findById = bookRepo.findById(bookingId);
if (findById.isPresent()) {
// System.out.println("Success in finding booking Id");
BookingDetails booking = findById.get();
// --- Slot Availability Check ---
String startDateStr = booking.getStartDate();
String endDateStr = booking.getEndDate();
int startingSlot = booking.getStartingSlot();
int endingSlot = booking.getEndingSlot();
int hallId = booking.getHallDetails().getHallId();
String currentBookingIdStr = String.valueOf(bookingId);
if (startDateStr != null && endDateStr != null) {
LocalDate startDate = LocalDate.parse(startDateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalDate endDate = LocalDate.parse(endDateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
int dayIndex = 0;
for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
BookingCalendar calEntry = bookingCalendarRepository.findByBdateAndHallId(date, hallId);
if (calEntry == null) {
dayIndex++;
continue; // No entry means this date is free
}
// Determine which slots are occupied by OTHER bookings (exclude this booking)
boolean morningOccupied = calEntry.isMorningSlot()
&& !currentBookingIdStr.equals(calEntry.getBookingId_1());
boolean eveningOccupied = calEntry.isEveningSlot()
&& !currentBookingIdStr.equals(calEntry.getBookingId_2());
boolean isConflict = false;
if (date.equals(startDate) && date.equals(endDate)) {
// Single-day booking
if (startingSlot == 1 && endingSlot == 2) {
// Full day needed - conflict if morning or evening is taken
isConflict = morningOccupied || eveningOccupied;
} else if (startingSlot == 1) {
isConflict = morningOccupied;
} else if (startingSlot == 2 || endingSlot == 2) {
isConflict = eveningOccupied;
}
} else if (date.equals(startDate)) {
// Start day of a multi-day booking
if (startingSlot == 1) {
// Morning start: needs morning + evening on start day
isConflict = morningOccupied || eveningOccupied;
} else {
// Evening start: needs only evening on start day
isConflict = eveningOccupied;
}
} else if (date.equals(endDate)) {
// End day of a multi-day booking
if (endingSlot == 1) {
// Morning end: needs only morning on end day
isConflict = morningOccupied;
} else {
// Evening end: needs both morning and evening on end day
isConflict = morningOccupied || eveningOccupied;
}
} else {
// Middle day: entire day must be free
isConflict = morningOccupied || eveningOccupied;
}
if (isConflict) {
hs.put("error", true);
hs.put("slotOccupied", true);
hs.put("occupiedDate", date.toString());
hs.put("message",
"The selected date " + date + " is already occupied. Please Change your dates.");
hs.put("hallId", hallId);
return hs;
}
dayIndex++;
}
}
// --- End Slot Availability Check ---
Users user = booking.getUsers();
int findUserId = user.getUserId();
// System.out.println("Merchant ID:-"+this.paymentConfig.getMerchantId());
String txnId="CHB"+transactionNumber.generateTransactionNumber()+String.format("%05d", findUserId); //create transaction Id unique from our side
String txnId = "CHB" + transactionNumber.generateTransactionNumber() + String.format("%05d", findUserId); // create
// unique
// transaction
// Id
// from
// our
// side
String totalAmt = String.valueOf(booking.getAmountReceived()); // Amount of Community Hall from our side
TransactionResponse response = new TransactionResponse();
response.setTxansactionId(txnId);
@ -152,13 +242,15 @@ public class PaymentAPIController {
response.setBookingId(bookingId);
this.paymentService.recordResponse(response);
String merchantId = this.paymentConfig.getMerchantId(); // This is Test Merchant ID from worldLine
String consumerId = String.format("%05d", findUserId); // Replace consumer ID in c964634 from our side
String consumerMobileNo=String.valueOf(user.getMobileNo()); //Replace consumer Mobile no in 9879879870 from our side
String consumerMobileNo = String.valueOf(user.getMobileNo()); // Replace consumer Mobile no in 9879879870
// from our side
String consumerEmailId = user.getEmail(); // replace consumer email Id
String encryptedtoken = this.paymentService.getToken(merchantId+"|", txnId+"|", totalAmt+"|", "|", consumerId+"|", consumerMobileNo+"|", consumerEmailId+"|", "|", "|", "|", "|", "|", "|", "|", "|", "|", this.paymentConfig.getEncryptionKey());
String encryptedtoken = this.paymentService.getToken(merchantId + "|", txnId + "|", totalAmt + "|", "|",
consumerId + "|", consumerMobileNo + "|", consumerEmailId + "|", "|", "|", "|", "|", "|", "|", "|",
"|", "|", this.paymentConfig.getEncryptionKey());
hs.put("txansactionId", txnId);
hs.put("token", encryptedtoken);
@ -168,22 +260,19 @@ public class PaymentAPIController {
hs.put("consumerEmailId", consumerEmailId);
hs.put("consumerId", consumerId);
hs.put("error", false);
}
else {
} else {
hs.put("error", true);
}
return hs;
}
@Operation(
summary = "Additional Damage payment-request REST API",
description = "REST API Additional Damage payment-request"
)
@Operation(summary = "Additional Damage payment-request REST API", description = "REST API Additional Damage payment-request")
@PostMapping(value = { "/additionaldamage-payment-request" })
public HashMap<String, Object> startextraPayment(int userId, int bookingId) throws NoSuchAlgorithmException {
//System.out.println("I entered payment Service......"+bookingId+ "User Id :- "+userId);
// System.out.println("I entered payment Service......"+bookingId+ "User Id :-
// "+userId);
HashMap<String, Object> hs = new HashMap<>();
Optional<BookingDetails> findById = bookRepo.findById(bookingId);
@ -194,8 +283,15 @@ public class PaymentAPIController {
int findUserId = user.getUserId();
// System.out.println("Merchant ID:-"+this.paymentConfig.getMerchantId());
String txnId="CHBED"+transactionNumber.generateTransactionNumber()+String.format("%05d", findUserId); //create transaction Id unique from our side
String totalAmt = String.valueOf(booking.getSettlement().getCollectionPending()); //Amount of Community Hall from our side
String txnId = "CHBED" + transactionNumber.generateTransactionNumber() + String.format("%05d", findUserId); // create
// transaction
// Id
// unique
// from
// our
// side
String totalAmt = String.valueOf(booking.getSettlement().getCollectionPending()); // Amount of Community
// Hall from our side
TransactionResponse response = new TransactionResponse();
response.setTxansactionId(txnId);
response.setHallId(booking.getHallDetails().getHallId());
@ -204,13 +300,15 @@ public class PaymentAPIController {
response.setBookingId(bookingId);
this.paymentService.recordResponse(response);
String merchantId = this.paymentConfig.getMerchantId(); // This is Test Merchant ID from worldLine
String consumerId = String.format("%05d", findUserId); // Replace consumer ID in c964634 from our side
String consumerMobileNo=String.valueOf(user.getMobileNo()); //Replace consumer Mobile no in 9879879870 from our side
String consumerMobileNo = String.valueOf(user.getMobileNo()); // Replace consumer Mobile no in 9879879870
// from our side
String consumerEmailId = user.getEmail(); // replace consumer email Id
String encryptedtoken = this.paymentService.getToken(merchantId+"|", txnId+"|", totalAmt+"|", "|", consumerId+"|", consumerMobileNo+"|", consumerEmailId+"|", "|", "|", "|", "|", "|", "|", "|", "|", "|", this.paymentConfig.getEncryptionKey());
String encryptedtoken = this.paymentService.getToken(merchantId + "|", txnId + "|", totalAmt + "|", "|",
consumerId + "|", consumerMobileNo + "|", consumerEmailId + "|", "|", "|", "|", "|", "|", "|", "|",
"|", "|", this.paymentConfig.getEncryptionKey());
System.out.println(totalAmt);
hs.put("txansactionId", txnId);
hs.put("token", encryptedtoken);
@ -220,8 +318,7 @@ public class PaymentAPIController {
hs.put("consumerEmailId", consumerEmailId);
hs.put("consumerId", consumerId);
hs.put("error", false);
}
else {
} else {
hs.put("error", true);
}

98
src/main/java/com/gcc/communityHall/paymentService/scheduler/PaymentStatusScheduler.java

@ -69,7 +69,8 @@ public class PaymentStatusScheduler {
@Autowired
private CalendarService calendarService;
// @Scheduled(cron = "0 0 0 * * ?", zone = "Asia/Kolkata") //executed at 12:00 AM
// @Scheduled(cron = "0 0 0 * * ?", zone = "Asia/Kolkata") //executed at 12:00
// AM
// @Scheduled(fixedRate = 900000)
@Scheduled(fixedRate = 60000)
public void fetchAndSavePaymentStatus() {
@ -77,7 +78,10 @@ public class PaymentStatusScheduler {
System.out.println("Fetching Payment Status...At 15 min Testing");
try {
List<Map<String, Object>> pendingTransactions = transactionResponseRepository.getTransResBycdateandStatus("temp");
List<Map<String, Object>> pendingTransactions = transactionResponseRepository
.getTransResBycdateandStatus("temp");
System.out.println("pendingTransactions size " + pendingTransactions.size() + "\n pendingTransactions list:"
+ pendingTransactions);
for (Map<String, Object> transactionRecord : pendingTransactions) {
try {
@ -94,7 +98,8 @@ public class PaymentStatusScheduler {
transaction.put("token", "");
transaction.put("reference", "");
System.out.println("=====================================" + transactionRecord.get("txansaction_id"));
System.out
.println("=====================================" + transactionRecord.get("txansaction_id"));
System.out.println(merchant);
System.out.println(transaction);
System.out.println(status);
@ -113,15 +118,16 @@ public class PaymentStatusScheduler {
transaction.put("dateTime", "");
}
Gson gson = new Gson();
String json = gson.toJson(status);
System.out.println("Hello json " + json);
String encryptHxRefund = paymentGatewayService.encryptHxRefund(json);
RestTemplate restTemplate = new RestTemplate();
String url = "https://www.tpsl-india.in/PaymentGateway/merchant2.pg/" + paymentConfig.getMerchantId();
ResponseEntity<String> postForEntity = restTemplate.postForEntity(url, encryptHxRefund, String.class);
String url = "https://www.tpsl-india.in/PaymentGateway/merchant2.pg/"
+ paymentConfig.getMerchantId();
ResponseEntity<String> postForEntity = restTemplate.postForEntity(url, encryptHxRefund,
String.class);
String decryptHxTRefund = paymentGatewayService.decryptHxTRefund(postForEntity.getBody());
Map<String, Object> myObj = new ObjectMapper().readValue(decryptHxTRefund, Map.class);
@ -149,9 +155,9 @@ public class PaymentStatusScheduler {
TransactionStatusLog saveLog = transactionStatusLogRepository.save(log);
TransactionResponse transRes = transactionResponseRepository.findById(Integer.parseInt(transactionRecord.get("id").toString())
).orElseThrow(() -> new Exception("TransactionResponse not found"));
TransactionResponse transRes = transactionResponseRepository
.findById(Integer.parseInt(transactionRecord.get("id").toString()))
.orElseThrow(() -> new Exception("TransactionResponse not found"));
transRes.setStatusCode(log.getStatusCode());
transRes.setAmount(log.getAmount());
@ -163,8 +169,8 @@ public class PaymentStatusScheduler {
transactionResponseRepository.save(transRes);
Payments payments = paymentsRepository.findByBookingId(Integer.valueOf(String.valueOf(transRes.getBookingId())));
Payments payments = paymentsRepository
.findByBookingId(Integer.valueOf(String.valueOf(transRes.getBookingId())));
System.out.println("payments hello" + payments);
if (payments != null && response.get("statusCode").toString().equals("0300")) {
@ -177,13 +183,15 @@ public class PaymentStatusScheduler {
// paymentsRepository.updatePaymentInfo(payments.getPaymentId(),payments.getTransactionId(),payments.getAmountReceived(),payments.getPaymentStatus(),transRes.getBookingId());
bookingService.updateBookingStatus(transRes.getBookingId(), BookingDetails.BookingStatus.REFUNDED, "Booking Not Confirmed. Amount will be refunded shortly.");
//intiateRefund(transRes.getBookingId(), Integer.parseInt(transRes.getUserId()));
bookingService.updateBookingStatus(transRes.getBookingId(),
BookingDetails.BookingStatus.REFUNDED,
"Booking Not Confirmed. Amount will be refunded shortly.");
// intiateRefund(transRes.getBookingId(),
// Integer.parseInt(transRes.getUserId()));
} else if (response.get("statusCode").toString().equals("0300")) {
payments = new Payments();
BookingDetails bookingsById = bookingService.getBookingsById(transRes.getBookingId());
payments.setBookingDetails(bookingsById);
payments.setTransactionId(transRes.getTxansactionId());
@ -191,20 +199,26 @@ public class PaymentStatusScheduler {
payments.setPaymentStatus("Success");
payments.setCdate(new Date());
//paymentsRepository.insertPaymentinfo(payments.getPaymentId(),payments.getTransactionId(),payments.getAmountReceived(),payments.getPaymentStatus(),transRes.getBookingId(),payments.getCdate() );
// paymentsRepository.insertPaymentinfo(payments.getPaymentId(),payments.getTransactionId(),payments.getAmountReceived(),payments.getPaymentStatus(),transRes.getBookingId(),payments.getCdate()
// );
bookingService.updateBookingStatus(transRes.getBookingId(), BookingDetails.BookingStatus.REFUNDED, "Booking Not Confirmed. Amount will be refunded shortly.");
// intiateRefund(transRes.getBookingId(), Integer.parseInt(transRes.getUserId()));
bookingService.updateBookingStatus(transRes.getBookingId(),
BookingDetails.BookingStatus.REFUNDED,
"Booking Not Confirmed. Amount will be refunded shortly.");
// intiateRefund(transRes.getBookingId(),
// Integer.parseInt(transRes.getUserId()));
} else {
payments.setBookingDetails(payments.getBookingDetails());
payments.setTransactionId(transRes.getTxansactionId());
payments.setAmountReceived(Double.parseDouble(response.get("amount") != null ? response.get("amount").toString() : "0"));
payments.setAmountReceived(Double
.parseDouble(response.get("amount") != null ? response.get("amount").toString() : "0"));
payments.setPaymentStatus("Not Completed");
payments.setCdate(new Date());
paymentsRepository.save(payments);
bookingService.updateBookingStatus(transRes.getBookingId(), BookingDetails.BookingStatus.PAYMENT_FAILURE, "Booking Not Confirmed. Amount Not Received.");
bookingService.updateBookingStatus(transRes.getBookingId(),
BookingDetails.BookingStatus.PAYMENT_FAILURE,
"Booking Not Confirmed. Amount Not Received.");
}
updateRefundInfo(response, log);
@ -219,10 +233,8 @@ public class PaymentStatusScheduler {
e.printStackTrace();
}
}
public void updateRefundInfo(Map<String, Object> response, TransactionStatusLog log) {
if (response.get("refundDdetails") != null) {
@ -233,7 +245,8 @@ public class PaymentStatusScheduler {
if (refundDetails != null && !refundDetails.isEmpty()) {
RefundResponse refundResponse = new RefundResponse();
refundResponse.setAmount(response.get("amount") != null ? response.get("amount").toString() : "");
refundResponse.setBalaceAmount(response.get("balanceAmount") != null ? response.get("balanceAmount").toString() : "");
refundResponse.setBalaceAmount(
response.get("balanceAmount") != null ? response.get("balanceAmount").toString() : "");
refundResponse.setTxansactionId(log.getTransactionId());
Map<String, Object> mapRef = refundDetails.get(refundDetails.size() - 1);
@ -258,7 +271,8 @@ public class PaymentStatusScheduler {
Double amt = Double.parseDouble(response.get("amount").toString());
Double balAmt = Double.parseDouble(response.get("balanceAmount").toString());
if (amt != balAmt) {
RefundTransaction refundTrans = transactionService.getRefundTrans(saverRefundResponse.getBookingId());
RefundTransaction refundTrans = transactionService
.getRefundTrans(saverRefundResponse.getBookingId());
if (refundTrans != null) {
refundTrans.setAmountRefunded(amt - balAmt);
@ -266,7 +280,6 @@ public class PaymentStatusScheduler {
refundTrans.setRefundIdentifier(response.get("refundIdentifier").toString());
refundTrans.setCdate(new Date());
transactionService.saveRefundTransaction(refundTrans);
} else {
refundTrans = new RefundTransaction();
@ -278,7 +291,8 @@ public class PaymentStatusScheduler {
refundTrans.setCdate(new Date());
refundTrans.setTransactionId(log.getTransactionId());
BookingDetails bookings = new BookingDetails();
BookingDetails bookingsById = bookingService.getBookingsById(Integer.parseInt(log.getBookingId()));
BookingDetails bookingsById = bookingService
.getBookingsById(Integer.parseInt(log.getBookingId()));
System.out.println("bookingsById" + bookingsById.getBookingId());
bookings.setBookingId(bookingsById.getBookingId());
refundTrans.setBookingDetails(bookings);
@ -286,37 +300,39 @@ public class PaymentStatusScheduler {
transactionService.saveRefundTransactionDetails(refundTrans);
}
// bookingService.updateRefundStatus(saverRefundResponse.getBookingId(), BookingDetails.RefundStatus.COMPLETED);
bookingService.updateRefundStatusScheduler(saverRefundResponse.getBookingId(), BookingDetails.RefundStatus.COMPLETED);
// bookingService.updateRefundStatus(saverRefundResponse.getBookingId(),
// BookingDetails.RefundStatus.COMPLETED);
bookingService.updateRefundStatusScheduler(saverRefundResponse.getBookingId(),
BookingDetails.RefundStatus.COMPLETED);
}
saveRefundClientInfo(refundDetails, log.getUserId(), log.getBookingId(), log.getTransactionId());
}
}
}
public String saveRefundClientInfo(List<Map<String, Object>> refundDetail, String userId, String bookingId, String transactionId) {
public String saveRefundClientInfo(List<Map<String, Object>> refundDetail, String userId, String bookingId,
String transactionId) {
if (refundDetail == null || refundDetail.isEmpty()) {
return "error";
}
for (Map<String, Object> refund : refundDetail) {
RefundClientInfo refundClientInfo = new RefundClientInfo();
refundClientInfo.setUserId(Integer.parseInt(userId));
refundClientInfo.setBookingId(Integer.parseInt(bookingId));
refundClientInfo.setTransactionId(transactionId);
refundClientInfo.setClntRfndId(refund.get("clnt_rfnd_id") != null ? refund.get("clnt_rfnd_id").toString() : "");
refundClientInfo
.setClntRfndId(refund.get("clnt_rfnd_id") != null ? refund.get("clnt_rfnd_id").toString() : "");
refundClientInfo.setArnNo(refund.get("ARN_Number") != null ? refund.get("ARN_Number").toString() : "");
refundClientInfo.setGetRefTxnDate(refund.get("REF_TXN_DATE") != null ? refund.get("REF_TXN_DATE").toString() : "");
refundClientInfo.setRefTxnAmt(refund.get("REF_TXN_AMT") != null ? refund.get("REF_TXN_AMT").toString() : "");
refundClientInfo
.setGetRefTxnDate(refund.get("REF_TXN_DATE") != null ? refund.get("REF_TXN_DATE").toString() : "");
refundClientInfo
.setRefTxnAmt(refund.get("REF_TXN_AMT") != null ? refund.get("REF_TXN_AMT").toString() : "");
refundClientInfo.setRefTxnId(refund.get("REF_TXN_ID") != null ? refund.get("REF_TXN_ID").toString() : "");
refundClientInfo.setStatus(refund.get("STATUS") != null ? refund.get("STATUS").toString() : "");
refundClientInfo.setSrno(refund.get("SR_NO") != null ? refund.get("SR_NO").toString() : "");
@ -334,17 +350,15 @@ public class PaymentStatusScheduler {
// if (bc != null && bc.isEmpty()) {
// String s = paymentGatewayServiceImpl.refundTheAmount(bookingId, userId);
// if (s.equals("Refunded")) {
// bookingService.updateRefundStatus(bookingId, BookingDetails.RefundStatus.COMPLETED);
// bookingService.updateRefundStatus(bookingId,
// BookingDetails.RefundStatus.COMPLETED);
// }
// } else {
// bookingService.updateRefundStatus(bookingId, BookingDetails.RefundStatus.FAILURE);
// bookingService.updateRefundStatus(bookingId,
// BookingDetails.RefundStatus.FAILURE);
// }
// }
}

6
src/main/java/com/gcc/communityHall/repository/BookingDetailsRepository.java

@ -1766,7 +1766,7 @@ public interface BookingDetailsRepository extends JpaRepository<BookingDetails,
"LEFT JOIN settlement s ON bd.booking_id = s.booking_details_booking_id " +
"LEFT JOIN transaction_response tr ON bd.booking_id = tr.booking_id " +
"WHERE datediff(CURRENT_DATE, bd.booking_date) > 180 " +
"AND bd.booking_status NOT IN ('PENDING','CANCELED','REJECTED') " +
"AND bd.booking_status IN ('APPROVED') and bd.refund_status in ('WAITING','FAILURE') " +
"AND (bd.mail_sent IS NULL OR bd.mail_sent = 0) " +
"ORDER BY bd.booking_id ASC", nativeQuery = true)
List<Map<String, Object>> findSixMonthOldNonCancelledRejectedBookings();
@ -1788,7 +1788,7 @@ public interface BookingDetailsRepository extends JpaRepository<BookingDetails,
"LEFT JOIN hall_details hd ON bd.hall_details_hall_id = hd.hall_id " +
"LEFT JOIN transaction_response tr ON bd.booking_id = tr.booking_id " +
"WHERE datediff(CURRENT_DATE, bd.booking_date) > 180 " +
"AND bd.booking_status = 'CANCELED' " +
"AND bd.booking_status = 'CANCELED' and bd.refund_status != 'COMPLETED' " +
"AND (bd.mail_sent IS NULL OR bd.mail_sent = 0) " +
"ORDER BY bd.booking_id ASC", nativeQuery = true)
List<Map<String, Object>> findSixMonthOldCancelledBookings();
@ -1810,7 +1810,7 @@ public interface BookingDetailsRepository extends JpaRepository<BookingDetails,
"LEFT JOIN hall_details hd ON bd.hall_details_hall_id = hd.hall_id " +
"LEFT JOIN transaction_response tr ON bd.booking_id = tr.booking_id " +
"WHERE datediff(CURRENT_DATE, bd.booking_date) > 180 " +
"AND bd.booking_status = 'REJECTED' " +
"AND bd.booking_status in ('REJECTED','GCC_BLOCKED') and bd.refund_status != 'COMPLETED' " +
"AND (bd.mail_sent IS NULL OR bd.mail_sent = 0) " +
"ORDER BY bd.booking_id ASC", nativeQuery = true)
List<Map<String, Object>> findSixMonthOldRejectedBookings();

8
src/main/java/com/gcc/communityHall/repository/LoginRepository.java

@ -13,13 +13,13 @@ import java.util.Map;
@Repository
public interface LoginRepository extends JpaRepository<Login, Long> {
@Query(value = "SELECT * FROM login where mobile_number=:mobileNo and password=:pin", nativeQuery = true)
@Query(value = "SELECT * FROM login where mobile_number=:mobileNo and password=:pin and is_active = 1 and is_delete = 0", nativeQuery = true)
Login findByMobileNoAndPin(long mobileNo, String pin);
@Query(value = "SELECT a FROM Login a WHERE a.mobileNumber = ?1")
@Query(value = "SELECT a FROM Login a WHERE a.mobileNumber = ?1 and a.isActive = true and a.isDelete = false")
Login checkUserbyMobile(long mobileNo);
@Query(value = "SELECT * FROM login where name=:username and password=:pass LIMIT 1", nativeQuery = true)
@Query(value = "SELECT * FROM login where name=:username and password=:pass and is_active = 1 and is_delete = 0 LIMIT 1", nativeQuery = true)
Login findByUsernameAndPass(String username, String pass);
@Query(value = "SELECT " +
@ -53,7 +53,7 @@ public interface LoginRepository extends JpaRepository<Login, Long> {
"ORDER BY cast(l.zone as unsigned)", nativeQuery = true)
List<Map<String, Object>> findActiveLogins();
@Query(value = "SELECT * FROM login WHERE id = :id", nativeQuery = true)
@Query(value = "SELECT * FROM login WHERE id = :id and is_active = 1 and is_delete = 0", nativeQuery = true)
Login findLoginById(int id);
@Query(value = "SELECT COUNT(*) FROM login WHERE mobile_number = :mobileNo AND is_delete = 0", nativeQuery = true)

9
src/main/java/com/gcc/communityHall/service/BookingService.java

@ -64,7 +64,8 @@ public interface BookingService {
int bookingId, int ebId,
double startingReading, double endingReading,
float usedUnit, double ebAmount,
String assetNames[], String comments[], int quantities[], Double assetAmounts[], MultipartFile assetImages[]);
String assetNames[], String comments[], int quantities[], Double assetAmounts[],
MultipartFile assetImages[]);
public int checkUserBookinglimitation(int userId);
@ -103,6 +104,9 @@ public interface BookingService {
Optional<String> updateBookingDatesAndCalendar(int bookingId, String startDate, String endDate);
Optional<String> updateBookingDatesAndCalendar(int bookingId, String startDate, String endDate,
int startingSlot, int endingSlot);
List<Object[]> getBookingHallDetailsReportByZone1(String fromDate, String toDate, String zone, Integer hallId);
List<Object> getGccBlockingEvents(String hallId);
@ -151,7 +155,8 @@ public interface BookingService {
List<Object[]> getAllPaymentsDetails(String fromDate, String toDate, String paymentStatus, String zone,
String division, Integer hallid);
List<Object[]> getBookingHallDetailsReportByBookingDate(String fromDate, String toDate, String zone, String division,
List<Object[]> getBookingHallDetailsReportByBookingDate(String fromDate, String toDate, String zone,
String division,
Integer hallid);
List<Object[]> getBookingHallDetailsReportByEventDate(String fromDate, String toDate, String zone, String division,

293
src/main/java/com/gcc/communityHall/service/Impl/BookingServiceImpl.java

@ -2288,6 +2288,154 @@ public class BookingServiceImpl implements BookingService {
return Optional.of("Booking not found.");
}
/**
* Overloaded version that also updates startingSlot and endingSlot.
* Used by the /reschedule-dates endpoint when the user has changed the slot.
*/
@Override
public Optional<String> updateBookingDatesAndCalendar(int bookingId, String startDat, String endDat,
int startingSlot, int endingSlot) {
// If slots are 0 (not provided by client), fall through to the existing method
if (startingSlot == 0 && endingSlot == 0) {
return updateBookingDatesAndCalendar(bookingId, startDat, endDat);
}
Optional<BookingDetails> optionalBookingDetails = bookingDetailsRepository.findById(bookingId);
if (optionalBookingDetails.isPresent()) {
BookingDetails bookingDetails = optionalBookingDetails.get();
String starting = bookingDetails.getStartDate();
int hallId = bookingDetails.getHallDetails().getHallId();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate startDate = LocalDate.parse(startDat, formatter);
LocalDate endDate = LocalDate.parse(endDat, formatter);
// Temporarily apply new slots for calendar-check logic
int origStartSlot = bookingDetails.getStartingSlot();
int origEndSlot = bookingDetails.getEndingSlot();
bookingDetails.setStartingSlot(startingSlot);
bookingDetails.setEndingSlot(endingSlot);
// Clear old calendar entries
List<BookingCalendar> existingCalendars = bookingCalendarRepository
.getCancellingdata1(String.valueOf(bookingId));
for (BookingCalendar calendar : existingCalendars) {
if (calendar.getBookingId_1() != null && calendar.getBookingId_1().equals(String.valueOf(bookingId))) {
calendar.setMorningSlot(false);
calendar.setBookingId_1(null);
}
if (calendar.getBookingId_2() != null && calendar.getBookingId_2().equals(String.valueOf(bookingId))) {
calendar.setEveningSlot(false);
calendar.setBookingId_2(null);
}
bookingCalendarRepository.save(calendar);
}
String slotOccExpMsg = "Dates are already occupied. Please select another date.";
int i = 0;
for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
BookingCalendar bookingCalendar = bookingCalendarRepository.findByBdateAndHallId(date, hallId);
if (bookingCalendar != null) {
if ((date.equals(startDate) && startingSlot == 1 && bookingCalendar.isMorningSlot()) ||
(date.equals(startDate) && startingSlot == 2 && bookingCalendar.isEveningSlot()) ||
(date.equals(endDate) && endingSlot == 1 && bookingCalendar.isMorningSlot()) ||
(date.equals(endDate) && endingSlot == 2 && bookingCalendar.isEveningSlot())) {
// Restore original slots before throwing
bookingDetails.setStartingSlot(origStartSlot);
bookingDetails.setEndingSlot(origEndSlot);
throw new SlotOccupiedException(slotOccExpMsg);
} else if (bookingCalendar.isMorningSlot() && bookingCalendar.isEveningSlot()) {
bookingDetails.setStartingSlot(origStartSlot);
bookingDetails.setEndingSlot(origEndSlot);
throw new SlotOccupiedException(slotOccExpMsg);
} else if (!date.equals(endDate) && i != 0 && i != Math.round(bookingDetails.getNoOfDays() - 1)
&& (bookingCalendar.isMorningSlot() || bookingCalendar.isEveningSlot())) {
bookingDetails.setStartingSlot(origStartSlot);
bookingDetails.setEndingSlot(origEndSlot);
throw new SlotOccupiedException(slotOccExpMsg);
} else if (date.equals(endDate) && endingSlot == 2 && bookingCalendar.isMorningSlot()
&& i != 0 && i == Math.round(bookingDetails.getNoOfDays() - 1)) {
bookingDetails.setStartingSlot(origStartSlot);
bookingDetails.setEndingSlot(origEndSlot);
throw new SlotOccupiedException(slotOccExpMsg);
}
} else {
String uniqueId = date.format(DateTimeFormatter.ofPattern("yyyyMMdd")) + hallId;
bookingCalendar = new BookingCalendar();
bookingCalendar.setBdate(date);
bookingCalendar.setHallId(hallId);
bookingCalendar.setIs_booked(0);
bookingCalendar.setIs_active(true);
bookingCalendar.setUnique_id(uniqueId);
}
// Mark slots
if (date.equals(startDate)) {
if (startingSlot == 1) {
bookingCalendar.setMorningSlot(true);
bookingCalendar.setBookingId_1(String.valueOf(bookingId));
bookingCalendar.setIs_booked(bookingCalendar.getIs_booked() + 1);
if (!date.equals(endDate)) {
bookingCalendar.setEveningSlot(true);
bookingCalendar.setBookingId_2(String.valueOf(bookingId));
bookingCalendar.setIs_booked(bookingCalendar.getIs_booked() + 1);
} else if (startDate.equals(endDate) && startingSlot == 1 && endingSlot == 2) {
bookingCalendar.setEveningSlot(true);
bookingCalendar.setBookingId_2(String.valueOf(bookingId));
bookingCalendar.setIs_booked(bookingCalendar.getIs_booked() + 1);
}
} else {
bookingCalendar.setEveningSlot(true);
bookingCalendar.setBookingId_2(String.valueOf(bookingId));
bookingCalendar.setIs_booked(bookingCalendar.getIs_booked() + 1);
}
} else if (date.equals(endDate)) {
if (endingSlot == 1) {
bookingCalendar.setMorningSlot(true);
bookingCalendar.setBookingId_1(String.valueOf(bookingId));
bookingCalendar.setIs_booked(bookingCalendar.getIs_booked() + 1);
} else {
bookingCalendar.setEveningSlot(true);
bookingCalendar.setBookingId_2(String.valueOf(bookingId));
bookingCalendar.setIs_booked(bookingCalendar.getIs_booked() + 1);
if (endingSlot == 2) {
bookingCalendar.setMorningSlot(true);
bookingCalendar.setBookingId_1(String.valueOf(bookingId));
bookingCalendar.setIs_booked(bookingCalendar.getIs_booked() + 1);
}
}
} else {
bookingCalendar.setMorningSlot(true);
bookingCalendar.setEveningSlot(true);
bookingCalendar.setBookingId_1(String.valueOf(bookingId));
bookingCalendar.setBookingId_2(String.valueOf(bookingId));
bookingCalendar.setIs_booked(bookingCalendar.getIs_booked() + 2);
}
bookingCalendarRepository.save(bookingCalendar);
i++;
}
// Persist new dates and slots
updateResheduledBookingDetails(bookingId, startDat, endDat, startingSlot, endingSlot);
String rescheduledmsg = "Your booking ID " + bookingId + " on " + starting
+ " has been successfully rescheduled to " + startDate
+ ". Thanks for using the GCC Community Hall Booking System.";
String urlString = "https://tmegov.onex-aura.com/api/sms?key=pfTEYN6H&to="
+ bookingDetails.getUsers().getMobileNo() + "&from=GCCCRP&body=" + rescheduledmsg
+ "&entityid=1401572690000011081&templateid=1407172346565044999";
String rescheduleMsg = "https://media.smsgupshup.com/GatewayAPI/rest?userid=2000233507&password=h2YjFNcJ&send_to="
+ bookingDetails.getUsers().getMobileNo()
+ "&v=1.1&format=json&msg_type=TEXT&method=SENDMESSAGE&msg=Your+booking+with+ID+" + bookingId
+ "+on+" + starting + "+has+been+successfully+rescheduled+to+" + startDate
+ "+.+%0AThank+you+for+using+the+GCC+Community+Hall+Booking+System.";
whatsappMsgServiceImpl.sendMsg(rescheduleMsg);
whatsappMsgServiceImpl.sendSMS(urlString);
return Optional.of("Booking dates updated successfully.");
}
return Optional.of("Booking not found.");
}
private void updateResheduledBookingDetails(int bookingId, String startDate, String endDate) {
Optional<BookingDetails> book = bookingDetailsRepository.findById(bookingId);
BookingDetails bookingDetails = book.get();
@ -2316,6 +2464,37 @@ public class BookingServiceImpl implements BookingService {
bookingHistoryRepository.save(bookingHistory);
}
/** Overload – also persists updated starting/ending slot values. */
private void updateResheduledBookingDetails(int bookingId, String startDate, String endDate,
int startingSlot, int endingSlot) {
Optional<BookingDetails> book = bookingDetailsRepository.findById(bookingId);
BookingDetails bookingDetails = book.get();
bookingDetails.setScheduleCount(bookingDetails.getScheduleCount() + 1);
if (bookingDetails.getReason().equals("Commercial") || bookingDetails.getReason().equals("State Govt Event")
|| bookingDetails.getReason().equals("Central Govt Event")) {
bookingDetails.setBookingStatus(BookingStatus.WAITING_FOR_NOC);
}
BookingHistory bookingHistory = new BookingHistory();
bookingHistory.setStartDate(bookingDetails.getStartDate());
bookingHistory.setEndDate(bookingDetails.getEndDate());
bookingHistory.setComments(bookingDetails.getComments());
bookingHistory.setBookingDetails(bookingDetails);
bookingHistory.setBookingStatus(BookingStatus.APPROVED);
bookingHistory.setUpdatedBy(userSession.getDispayName());
bookingHistory.setCdate(new Date());
bookingHistory.setRefundStatus(bookingDetails.getRefundStatus());
bookingDetails.setStartDate(startDate);
bookingDetails.setEndDate(endDate);
// ── Persist the updated slots ──────────────────────────────────────
bookingDetails.setStartingSlot(startingSlot);
bookingDetails.setEndingSlot(endingSlot);
bookingDetails.setComments("slots Resheduled the Dates");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
bookingDetails.setUpdatedDate(LocalDateTime.now().format(formatter));
bookingDetailsRepository.save(bookingDetails);
bookingHistoryRepository.save(bookingHistory);
}
@Override
public List<Object[]> getBookingHallDetailsReportByZone1(String fromDate, String toDate, String zone,
Integer hallId) {
@ -2361,15 +2540,8 @@ public class BookingServiceImpl implements BookingService {
String reasonforblocking, List<String> selectedBookings, String updatedBy, String[] descriptions,
MultipartFile[] documents) {
if (selectedBookings != null && !selectedBookings.isEmpty()) {
// ── Collect cancelled user booking IDs (used later to build ONE GCC record) ──
List<Integer> cancelledBookingIds = new ArrayList<>();
// ── Phase 1: Cancel each selected booking (BookingDetails + BookingCalendar
// slots) ──
for (String bookingIdStr : selectedBookings) {
Integer bookingId = Integer.parseInt(bookingIdStr);
System.out.println("bookingId..." + bookingId);
Optional<BookingDetails> optionalBooking = bookingDetailsRepository.findById(bookingId);
if (optionalBooking.isPresent()) {
@ -2395,33 +2567,7 @@ public class BookingServiceImpl implements BookingService {
updateBookingStatus(bb);
}
updateBookingStatusById(booking.getBookingId(), BookingStatus.GCC_BLOCKED,
reasonforblocking);
// WhatsApp msg and SMS
String gccblockedsms = "Your booking ID " + bookingId + " on " + booking.getStartDate()
+ " has been blocked by GCC due to " + reasonforblocking
+ ". The entire amount paid will be refunded to your account with in 3 to 15 days.";
String gccblockedurlString = "https://tmegov.onex-aura.com/api/sms?key=pfTEYN6H&to="
+ booking.getUsers().getMobileNo() + "&from=GCCCRP&body=" + gccblockedsms
+ "&entityid=1401572690000011081&templateid=1407172346521513227";
// String
// gccblockedwhatsupmsg="https://media.smsgupshup.com/GatewayAPI/rest?userid=2000233507&password=h2YjFNcJ&send_to="+booking.getUsers().getMobileNo()+"&v=1.1&format=json&msg_type=TEXT&method=SENDMESSAGE&msg=Your+booking+with+ID+"+booking.getBookingId()+"+on+"+booking.getBookingDate()+"+has+been+blocked+by+GCC+due+to+"+reasonforblocking+".+%0AThanks+for+using+GCC+Community+Hall+Booking+System.";
String gccblockedwhatsupmsg = "https://media.smsgupshup.com/GatewayAPI/rest?userid=2000233507&password=h2YjFNcJ&send_to="
+ booking.getUsers().getMobileNo()
+ "&v=1.1&format=json&msg_type=TEXT&method=SENDMESSAGE&msg=Your+booking+with+ID+"
+ booking.getBookingId() + "+on+" + booking.getStartDate()
+ "+has+been+blocked+by+the+GCC+due+to+Goverment+event++.+%0AThe+entire+amount+paid+will+be+refunded+to+your+account+within+3+to+15+days.";
whatsappMsgServiceImpl.sendMsg(gccblockedwhatsupmsg);
whatsappMsgServiceImpl.sendSMS(gccblockedurlString);
bookingDetailsRepository.save(booking);
cancelledBookingIds.add(bookingId);
}
}
}
// ── Phase 2: Create ONE GccBlockingDate record for the entire operation ──
// GCC blocking entry
GccBlockingDate gcc = new GccBlockingDate();
gcc.setStartDate(convertStringToDate(fromDate));
gcc.setEndDate(convertStringToDate(toDate));
@ -2430,8 +2576,6 @@ public class BookingServiceImpl implements BookingService {
gcc.setUpdatedBy(updatedBy);
gcc.setCdate(new Date());
gcc.setBlockingReason(reasonforblocking);
// Save document(s) if present
if (documents != null && documents.length > 0 && descriptions != null
&& descriptions.length > 0) {
int i = 0;
@ -2440,14 +2584,24 @@ public class BookingServiceImpl implements BookingService {
+ document.getOriginalFilename();
String documentUrl = serverPath + "gccblockingdocs/" + gcc.getBlockingId() + "_" + i
+ "_" + document.getOriginalFilename();
try (FileOutputStream fos = new FileOutputStream(filePath)) {
// Save document to the file system
byte[] bytes = document.getBytes();
fos.write(bytes);
GccblockingDocuments documentDetails = new GccblockingDocuments();
documentDetails.setBlockingDate(gcc);
documentDetails.setBlockingDocument(documentUrl);
documentDetails.setDescription(descriptions[i]);
gccblockingDocumentsRepo.save(documentDetails);
// Save document details along with description in the database
GccblockingDocuments documentDetails = new GccblockingDocuments(); // Assuming you
// have a
// DocumentDetails
// entity
documentDetails.setBlockingDate(gcc); // Assuming hallDetails is associated with the
// document
documentDetails.setBlockingDocument(documentUrl); // Save the URL of the uploaded
// document
documentDetails.setDescription(descriptions[i]); // Save corresponding description
gccblockingDocumentsRepo.save(documentDetails); // Save the document and description
// in the database
} catch (IOException e) {
throw new RuntimeException("Failed to save document", e);
}
@ -2455,19 +2609,7 @@ public class BookingServiceImpl implements BookingService {
}
}
// Save the single GCC blocking record
List<Integer> gccBookingIds = saveGCCBlockingDate(gcc);
// Store the actual cancelled user booking IDs on the gcc record
if (!cancelledBookingIds.isEmpty()) {
String cancelledIdsStr = cancelledBookingIds.stream()
.map(String::valueOf)
.collect(Collectors.joining(","));
gcc.setBookingIds(cancelledIdsStr);
gccBlockingDateRepository.save(gcc);
}
// GCC Blocking History — one entry for the whole operation
// GCC blocking History
GccBlockingHistory gccblockinghistory = new GccBlockingHistory();
gccblockinghistory.setStartDate(convertStringToDate(fromDate));
gccblockinghistory.setEndDate(convertStringToDate(toDate));
@ -2476,29 +2618,31 @@ public class BookingServiceImpl implements BookingService {
gccblockinghistory.setUpdatedBy(updatedBy);
gccblockinghistory.setCdate(new Date());
gccblockinghistory.setBlockingReason(reasonforblocking);
gccblockinghistory.setBookingIds(cancelledBookingIds.stream()
.map(String::valueOf).collect(Collectors.joining(",")));
List<Integer> bookingIds = saveGCCBlockingDate(gcc);
gccblockinghistory.setBookingIds(bookingIds.toString());
blockingHistoryRepository.save(gccblockinghistory);
// ── Phase 3: Update BookingCalendar (mark dates as GCC-blocked) ──
// GCC calendar
for (Long hallId : hallIdsList) {
LocalDate fDate = LocalDate.parse(fromDate);
LocalDate tDate = LocalDate.parse(toDate);
List<LocalDate> dates = getDateRange(fDate, tDate);
for (LocalDate aa : dates) {
String uniqueId = aa.format(DateTimeFormatter.ofPattern("yyyyMMdd")) + hallId;
BookingCalendar data = getbyDates(aa, hallId.toString());
int userbookingbookingId = gccBookingIds.get(hallIdsList.indexOf(hallId));
int userbookingbookingId = bookingIds.get(hallIdsList.indexOf(hallId));
if (data != null) {
// data.setBookingId_1(String.valueOf(userbookingbookingId));
// data.setBookingId_2(String.valueOf(userbookingbookingId));
// data.setMorningSlot(true);
// data.setEveningSlot(true);
System.out.println("uniqueId...1" + uniqueId);
data.setBookingId_1(String.valueOf(userbookingbookingId));
data.setBookingId_2(String.valueOf(userbookingbookingId));
data.setMorningSlot(true);
data.setEveningSlot(true);
data.setIs_blocked(true);
data.setUnique_id(uniqueId);
updateBookingStatus(data);
} else {
System.out.println("uniqueId...2" + uniqueId);
BookingCalendar book = new BookingCalendar();
book.setBdate(aa);
book.setBookingId_1(String.valueOf(userbookingbookingId));
@ -2515,6 +2659,29 @@ public class BookingServiceImpl implements BookingService {
}
}
}
updateBookingStatusById(booking.getBookingId(), booking.getBookingStatus().GCC_BLOCKED,
reasonforblocking);
// whatsup msg and SMS
String gccblockedsms = "Your booking ID " + bookingId + " on " + booking.getStartDate()
+ " has been blocked by GCC due to " + reasonforblocking
+ ". The entire amount paid will be refunded to your account with in 3 to 15 days.";
String gccblockedurlString = "https://tmegov.onex-aura.com/api/sms?key=pfTEYN6H&to="
+ booking.getUsers().getMobileNo() + "&from=GCCCRP&body=" + gccblockedsms
+ "&entityid=1401572690000011081&templateid=1407172346521513227";
// String
// gccblockedwhatsupmsg="https://media.smsgupshup.com/GatewayAPI/rest?userid=2000233507&password=h2YjFNcJ&send_to="+booking.getUsers().getMobileNo()+"&v=1.1&format=json&msg_type=TEXT&method=SENDMESSAGE&msg=Your+booking+with+ID+"+booking.getBookingId()+"+on+"+booking.getBookingDate()+"+has+been+blocked+by+GCC+due+to+"+reasonforblocking+".+%0AThanks+for+using+GCC+Community+Hall+Booking+System.";
String gccblockedwhatsupmsg = "https://media.smsgupshup.com/GatewayAPI/rest?userid=2000233507&password=h2YjFNcJ&send_to="
+ booking.getUsers().getMobileNo()
+ "&v=1.1&format=json&msg_type=TEXT&method=SENDMESSAGE&msg=Your+booking+with+ID+"
+ booking.getBookingId() + "+on+" + booking.getStartDate()
+ "+has+been+blocked+by+the+GCC+due+to+Goverment+event++.+%0AThe+entire+amount+paid+will+be+refunded+to+your+account+within+3+to+15+days.";
whatsappMsgServiceImpl.sendMsg(gccblockedwhatsupmsg);
whatsappMsgServiceImpl.sendSMS(gccblockedurlString);
bookingDetailsRepository.save(booking);
}
}
}
} else {
// Create and save a new GCC blocking date record
GccBlockingDate gcc = new GccBlockingDate();

2
src/main/java/com/gcc/communityHall/service/MailService.java

@ -46,7 +46,7 @@ public class MailService {
}
}
helper.setSubject("Test Mail Refund Status Update Request - Community Hall Booking");
helper.setSubject("Refund Status Update Request - Community Hall Booking");
DecimalFormat df = new DecimalFormat("#,##0.00");
String amt = (refundAmount != null) ? "Rs. " + df.format(refundAmount) : "N/A";

843
src/main/resources/resources/templates/headquarters/sixmonthold-transactions.html

@ -1,843 +0,0 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="~{fragments/head-headquarters :: head}"></head>
<style>
.nav-tabs .nav-link.active {
background: #1a73e8;
color: #fff !important;
border-color: #1a73e8;
border-radius: 6px 6px 0 0;
}
.nav-tabs .nav-link {
color: #444;
font-weight: 500;
}
.tab-badge {
background: #e8f0fe;
color: #1a73e8;
border-radius: 10px;
padding: 1px 8px;
font-size: 12px;
font-weight: 700;
margin-left: 4px;
}
.nav-tabs .nav-link.active .tab-badge {
background: rgba(255, 255, 255, 0.25);
color: #fff;
}
.table-responsive {
overflow-x: auto;
}
.card-body table {
width: 100%;
}
.card-body th,
td {
padding: 8px;
text-align: left;
}
.amount-cell {
text-align: right;
padding-right: 1rem;
}
.table {
width: 100% !important;
}
.btn-sendmail {
background: #1a73e8;
color: #fff;
border: none;
border-radius: 4px;
padding: 3px 10px;
cursor: pointer;
font-size: 12px;
}
.btn-sendmail:hover {
background: #1558b0;
}
.btn-viewdetails {
background: #f59e0b;
color: #fff;
border: none;
border-radius: 4px;
padding: 3px 10px;
cursor: pointer;
font-size: 12px;
margin-right: 4px;
}
.btn-viewdetails:hover {
background: #b45309;
}
.badge-cancelled {
background: #dc2626;
color: #fff;
padding: 3px 8px;
border-radius: 10px;
font-size: 11px;
}
.badge-rejected {
background: #7c3aed;
color: #fff;
padding: 3px 8px;
border-radius: 10px;
font-size: 11px;
}
.badge-approved {
background: #16a34a;
color: #fff;
padding: 3px 8px;
border-radius: 10px;
font-size: 11px;
}
.badge-other {
background: #64748b;
color: #fff;
padding: 3px 8px;
border-radius: 10px;
font-size: 11px;
}
.not-initiated {
color: #dc2626;
font-style: italic;
font-size: 12px;
}
/* Draft mail preview */
#draftMailBody {
background: #f8fafc;
border: 1px solid #cbd5e1;
border-radius: 6px;
padding: 16px;
font-family: Arial, sans-serif;
font-size: 14px;
white-space: pre-wrap;
line-height: 1.6;
}
.mail-header-row {
margin-bottom: 6px;
font-size: 13px;
}
.mail-header-row strong {
display: inline-block;
width: 50px;
color: #475569;
}
</style>
<body>
<!-- Page Container -->
<div id="page-container"
class="sidebar-o sidebar-dark enable-page-overlay side-scroll page-header-fixed page-header-dark">
<!-- Side Overlay aside (right)-->
<aside th:replace="~{fragments/aside-right :: aside}"></aside>
<!-- END Side Overlay (right)-->
<!-- Sidebar Nav-->
<nav th:replace="~{fragments/nav-headquarters :: nav}"></nav>
<!-- END Sidebar -->
<!-- Header -->
<header th:replace="~{fragments/header-headquarters :: header}"></header>
<!-- END Header -->
<!-- Main Container -->
<main id="main-container" class="container-fluid mt-4 px-4">
<div class="block block-rounded">
<div class="block-header block-header-default">
<h3 class="block-title">6 Months Old Transaction Details</h3>
</div>
<div class="block-content">
<!-- ── TABS ───────────────────────────────────────────── -->
<ul class="nav nav-tabs mb-0" id="sixMonthTab" role="tablist">
<li class="nav-item" role="presentation">
<a class="nav-link active" id="tab-sixmonth-lnk" data-toggle="tab" href="#tab-sixmonth"
role="tab" aria-controls="tab-sixmonth" aria-selected="true">
6 Month Old Bookings
<span class="tab-badge"
th:text="${sixMonthOldBookings != null ? #lists.size(sixMonthOldBookings) : 0}">0</span>
</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="tab-cancelled-lnk" data-toggle="tab" href="#tab-cancelled"
role="tab" aria-controls="tab-cancelled" aria-selected="false">
Cancelled Bookings
<span class="tab-badge"
th:text="${cancelledBookings != null ? #lists.size(cancelledBookings) : 0}">0</span>
</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="tab-rejected-lnk" data-toggle="tab" href="#tab-rejected"
role="tab" aria-controls="tab-rejected" aria-selected="false">
Rejected Bookings
<span class="tab-badge"
th:text="${rejectedBookings != null ? #lists.size(rejectedBookings) : 0}">0</span>
</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="tab-mailsent-lnk" data-toggle="tab" href="#tab-mailsent"
role="tab" aria-controls="tab-mailsent" aria-selected="false">
Mail Sent Bookings
<span class="tab-badge"
th:text="${mailSentBookings != null ? #lists.size(mailSentBookings) : 0}">0</span>
</a>
</li>
</ul>
<div class="tab-content border border-top-0 p-3" id="sixMonthTabContent">
<!-- ══════════════════════════════════════════════════
TAB 1 – 6 Month Old Bookings (non-cancelled/rejected)
══════════════════════════════════════════════════ -->
<div class="tab-pane fade show active" id="tab-sixmonth" role="tabpanel" aria-labelledby="tab-sixmonth-lnk">
<div class="table-responsive">
<table class="table table-bordered table-striped table-vcenter js-dataTable-responsive"
id="tbl-sixmonth">
<thead class="thead-light">
<tr>
<th>S.No</th>
<th>Zone</th>
<th>Division</th>
<th>Hall Name</th>
<th>Booking Date</th>
<th>Event Date (Start – End)</th>
<th>Settlement Raised Date</th>
<th>Refund Amount (₹)</th>
<th>Refund Status</th>
<th>Booking Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr th:each="row, rowStat : ${sixMonthOldBookings}">
<td class="text-center" th:text="${rowStat.index + 1}"></td>
<td th:text="${row['zone'] != null ? row['zone'] : ''}"></td>
<td th:text="${row['division'] != null ? row['division'] : ''}"></td>
<td th:text="${row['hall_name'] != null ? row['hall_name'] : ''}"></td>
<td class="text-center"
th:text="${row['booking_date'] != null ? row['booking_date'] : ''}">
</td>
<td class="text-center"
th:text="(${row['event_start_date'] != null ? row['event_start_date'] : ''}) + ' – ' + (${row['event_end_date'] != null ? row['event_end_date'] : ''})">
</td>
<!-- Settlement Raised Date: N/A if no settlement -->
<td class="text-center">
<span th:if="${row['settlement_raised_date'] != null}"
th:text="${row['settlement_raised_date']}"></span>
<span th:if="${row['settlement_raised_date'] == null}"
class="not-initiated">Settlement Not Initiated</span>
</td>
<!-- Refund Amount: from settlement.refunded_amount -->
<td class="text-right">
<span th:if="${row['refunded_amount'] != null}"
th:text="'₹ ' + ${row['refunded_amount']}"></span>
<span th:if="${row['refunded_amount'] == null}"
class="not-initiated">—</span>
</td>
<td class="text-center"
th:text="${row['refund_status'] != null ? row['refund_status'] : ''}">
</td>
<td class="text-center">
<span th:classappend="${row['booking_status'] == 'CANCELED' || row['booking_status'] == 'CANCELLED'} ? 'badge-cancelled' :
(${row['booking_status'] == 'REJECTED'} ? 'badge-rejected' :
(${row['booking_status'] == 'APPROVED'} ? 'badge-approved' : 'badge-other'))"
th:text="${row['booking_status'] != null ? row['booking_status'] : ''}"></span>
</td>
<td class="text-center">
<!-- View Details: calls getSettlementList if settlement exists -->
<button th:if="${row['settlement_id'] != null}" class="btn-viewdetails"
th:onclick="|viewSettlement(${row['settlement_id']})|">
View Details
</button>
<span th:if="${row['settlement_id'] == null}"
class="not-initiated d-block mb-1">Settlement Not Initiated</span>
<button class="btn-sendmail"
th:onclick="|openSendMail(${row['booking_id'] != null ? row['booking_id'] : 0}, '${row['booking_status'] != null ? row['booking_status'] : ''}', '${row['txansaction_id'] != null ? row['txansaction_id'] : ''}', '${row['tpsl_txn_id'] != null ? row['tpsl_txn_id'] : ''}', '${row['transaction_date'] != null ? row['transaction_date'] : ''}', ${row['refunded_amount'] != null ? row['refunded_amount'] : 0})|">
Send Mail
</button>
</td>
</tr>
<tr
th:if="${sixMonthOldBookings == null || #lists.isEmpty(sixMonthOldBookings)}">
<td colspan="11" class="text-center text-muted py-3">No records found</td>
</tr>
</tbody>
</table>
</div>
</div><!-- /tab-sixmonth -->
<!-- ══════════════════════════════════════════════════
TAB 2 – Cancelled Bookings
Refund Amount = deposit_amount
No Settlement Raised Date column
══════════════════════════════════════════════════ -->
<div class="tab-pane fade" id="tab-cancelled" role="tabpanel" aria-labelledby="tab-cancelled-lnk">
<div class="table-responsive">
<table class="table table-bordered table-striped table-vcenter js-dataTable-responsive"
id="tbl-cancelled">
<thead class="thead-light">
<tr>
<th>S.No</th>
<th>Zone</th>
<th>Division</th>
<th>Hall Name</th>
<th>Booking Date</th>
<th>Event Date (Start – End)</th>
<th>Refund Amount (₹)</th>
<th>Booking Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr th:each="row, rowStat : ${cancelledBookings}">
<td class="text-center" th:text="${rowStat.index + 1}"></td>
<td th:text="${row['zone'] != null ? row['zone'] : ''}"></td>
<td th:text="${row['division'] != null ? row['division'] : ''}"></td>
<td th:text="${row['hall_name'] != null ? row['hall_name'] : ''}"></td>
<td class="text-center"
th:text="${row['booking_date'] != null ? row['booking_date'] : ''}">
</td>
<td class="text-center"
th:text="(${row['event_start_date'] != null ? row['event_start_date'] : ''}) + ' – ' + (${row['event_end_date'] != null ? row['event_end_date'] : ''})">
</td>
<td class="text-right"
th:text="${row['refund_amount'] != null ? '₹ ' + row['refund_amount'] : '—'}">
</td>
<td class="text-center">
<span class="badge-cancelled"
th:text="${row['booking_status'] != null ? row['booking_status'] : ''}"></span>
</td>
<td class="text-center">
<button class="btn-viewdetails"
th:onclick="|viewBookingDetails(${row['booking_id'] != null ? row['booking_id'] : 0})|">
View Details
</button>
<button class="btn-sendmail"
th:onclick="|openSendMail(${row['booking_id'] != null ? row['booking_id'] : 0}, '${row['booking_status'] != null ? row['booking_status'] : ''}', '${row['txansaction_id'] != null ? row['txansaction_id'] : ''}', '${row['tpsl_txn_id'] != null ? row['tpsl_txn_id'] : ''}', '${row['transaction_date'] != null ? row['transaction_date'] : ''}', ${row['refund_amount'] != null ? row['refund_amount'] : 0})|">
Send Mail
</button>
</td>
</tr>
<tr th:if="${cancelledBookings == null || #lists.isEmpty(cancelledBookings)}">
<td colspan="9" class="text-center text-muted py-3">No records found</td>
</tr>
</tbody>
</table>
</div>
</div><!-- /tab-cancelled -->
<!-- ══════════════════════════════════════════════════
TAB 3 – Rejected Bookings
Refund Amount = amount_received (full amount)
No Settlement Raised Date column
══════════════════════════════════════════════════ -->
<div class="tab-pane fade" id="tab-rejected" role="tabpanel" aria-labelledby="tab-rejected-lnk">
<div class="table-responsive">
<table class="table table-bordered table-striped table-vcenter js-dataTable-responsive"
id="tbl-rejected">
<thead class="thead-light">
<tr>
<th>S.No</th>
<th>Zone</th>
<th>Division</th>
<th>Hall Name</th>
<th>Booking Date</th>
<th>Event Date (Start – End)</th>
<th>Refund Amount (₹)</th>
<th>Booking Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr th:each="row, rowStat : ${rejectedBookings}">
<td class="text-center" th:text="${rowStat.index + 1}"></td>
<td th:text="${row['zone'] != null ? row['zone'] : ''}"></td>
<td th:text="${row['division'] != null ? row['division'] : ''}"></td>
<td th:text="${row['hall_name'] != null ? row['hall_name'] : ''}"></td>
<td class="text-center"
th:text="${row['booking_date'] != null ? row['booking_date'] : ''}">
</td>
<td class="text-center"
th:text="(${row['event_start_date'] != null ? row['event_start_date'] : ''}) + ' – ' + (${row['event_end_date'] != null ? row['event_end_date'] : ''})">
</td>
<td class="text-right"
th:text="${row['refund_amount'] != null ? '₹ ' + row['refund_amount'] : '—'}">
</td>
<td class="text-center">
<span class="badge-rejected"
th:text="${row['booking_status'] != null ? row['booking_status'] : ''}"></span>
</td>
<td class="text-center">
<button class="btn-viewdetails"
th:onclick="|viewBookingDetails(${row['booking_id'] != null ? row['booking_id'] : 0})|">
View Details
</button>
<button class="btn-sendmail"
th:onclick="|openSendMail(${row['booking_id'] != null ? row['booking_id'] : 0}, '${row['booking_status'] != null ? row['booking_status'] : ''}', '${row['txansaction_id'] != null ? row['txansaction_id'] : ''}', '${row['tpsl_txn_id'] != null ? row['tpsl_txn_id'] : ''}', '${row['transaction_date'] != null ? row['transaction_date'] : ''}', ${row['refund_amount'] != null ? row['refund_amount'] : 0})|">
Send Mail
</button>
</td>
</tr>
<tr th:if="${rejectedBookings == null || #lists.isEmpty(rejectedBookings)}">
<td colspan="9" class="text-center text-muted py-3">No records found</td>
</tr>
</tbody>
</table>
</div>
</div><!-- /tab-rejected -->
<!-- ══════════════════════════════════════════════════
TAB 4 – Mail Sent Bookings
══════════════════════════════════════════════════ -->
<div class="tab-pane fade" id="tab-mailsent" role="tabpanel" aria-labelledby="tab-mailsent-lnk">
<div class="table-responsive">
<table class="table table-bordered table-striped table-vcenter js-dataTable-responsive"
id="tbl-mailsent">
<thead class="thead-light">
<tr>
<th>S.No</th>
<th>Zone</th>
<th>Division</th>
<th>Hall Name</th>
<th>Booking Date</th>
<th>Event Date (Start – End)</th>
<th>Booking Status</th>
<th>Transaction ID</th>
<th>TPSL ID</th>
<th>Mail Sent Date</th>
</tr>
</thead>
<tbody>
<tr th:each="row, rowStat : ${mailSentBookings}">
<td class="text-center" th:text="${rowStat.index + 1}"></td>
<td th:text="${row['zone'] != null ? row['zone'] : ''}"></td>
<td th:text="${row['division'] != null ? row['division'] : ''}"></td>
<td th:text="${row['hall_name'] != null ? row['hall_name'] : ''}"></td>
<td class="text-center"
th:text="${row['booking_date'] != null ? row['booking_date'] : ''}">
</td>
<td class="text-center"
th:text="(${row['event_start_date'] != null ? row['event_start_date'] : ''}) + ' – ' + (${row['event_end_date'] != null ? row['event_end_date'] : ''})">
</td>
<td class="text-center">
<span th:classappend="${row['booking_status'] == 'CANCELED' || row['booking_status'] == 'CANCELLED'} ? 'badge-cancelled' :
(${row['booking_status'] == 'REJECTED'} ? 'badge-rejected' :
(${row['booking_status'] == 'APPROVED'} ? 'badge-approved' : 'badge-other'))"
th:text="${row['booking_status'] != null ? row['booking_status'] : ''}"></span>
</td>
<td class="text-center"
th:text="${row['txansaction_id'] != null ? row['txansaction_id'] : ''}">
</td>
<td class="text-center"
th:text="${row['tpsl_txn_id'] != null ? row['tpsl_txn_id'] : ''}"></td>
<td class="text-center"
th:text="${row['mail_sent_date'] != null ? row['mail_sent_date'] : ''}">
</td>
</tr>
<tr th:if="${mailSentBookings == null || #lists.isEmpty(mailSentBookings)}">
<td colspan="10" class="text-center text-muted py-3">No records found</td>
</tr>
</tbody>
</table>
</div>
</div><!-- /tab-mailsent -->
</div><!-- /tab-content -->
</div><!-- /block-content -->
</div><!-- /block -->
</main>
<!-- END Main Container -->
<!-- ══════════════════════════════════════════════════════════════════
MODAL – Settlement View Details (Tab 1 with settlement)
══════════════════════════════════════════════════════════════════ -->
<div class="modal fade" id="settlementModal" data-backdrop="static" tabindex="-1" role="dialog"
aria-labelledby="settlementModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="block block-rounded block-themed block-transparent mb-0">
<div class="block-header bg-primary-dark">
<h3 class="block-title" id="settlementModalLabel">Settlement Information</h3>
<div class="block-options">
<button type="button" class="btn-block-option" data-dismiss="modal" aria-label="Close">
<i class="fa fa-fw fa-times"></i>
</button>
</div>
</div>
<div class="block-content row p-3" id="settlementModalBody">
<!-- Populated by JS -->
</div>
<div class="block-content block-content-full text-right bg-body">
<button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
<!-- ══════════════════════════════════════════════════════════════════
MODAL – Booking View Details (Tab 2 & 3 – cancelled/rejected)
══════════════════════════════════════════════════════════════════ -->
<div class="modal fade" id="bookingModal" data-backdrop="static" tabindex="-1" role="dialog"
aria-labelledby="bookingModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="block block-rounded block-themed block-transparent mb-0">
<div class="block-header bg-primary-dark">
<h3 class="block-title" id="bookingModalLabel">Booking Information</h3>
<div class="block-options">
<button type="button" class="btn-block-option" data-dismiss="modal" aria-label="Close">
<i class="fa fa-fw fa-times"></i>
</button>
</div>
</div>
<div class="block-content row p-3" id="bookingModalBody">
<!-- Populated by JS -->
</div>
<div class="block-content block-content-full text-right bg-body">
<button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
<!-- ══════════════════════════════════════════════════════════════════
MODAL – Draft Mail Preview & Confirm
══════════════════════════════════════════════════════════════════ -->
<div class="modal fade" id="draftMailModal" data-backdrop="static" tabindex="-1" role="dialog"
aria-labelledby="draftMailModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header" style="background:#1a73e8; color:#fff;">
<h5 class="modal-title" id="draftMailModalLabel">
<i class="fa fa-envelope mr-2"></i>Draft Mail Preview
</h5>
<button type="button" class="close text-white" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<!-- Mail Header Fields -->
<div class="mail-header-row"><strong>From:</strong>
communityhallsupport@chennaicorporation.gov.in</div>
<div class="mail-header-row">
<strong>To:</strong>
pgsupport@mail.in.worldline-solutions.com, ranjithkumar@federal.bank.in,
megha.mattamana@federal.bank.in
</div>
<div class="mail-header-row">
<strong>CC:</strong>
arohqcc@gmail.com, it@chennaicorporation.gov.in
</div>
<div class="mail-header-row"><strong>Sub:</strong> Refund Status Update Request – Community Hall
Booking</div>
<hr class="my-2">
<!-- Mail Body -->
<div id="draftMailBody"></div>
<!-- Hidden fields to carry data through to confirm step -->
<input type="hidden" id="dm_bookingId">
<input type="hidden" id="dm_bookingStatus">
<input type="hidden" id="dm_transactionId">
<input type="hidden" id="dm_tpslId">
<input type="hidden" id="dm_refundAmount">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
<i class="fa fa-times mr-1"></i>Close
</button>
<button type="button" class="btn btn-primary" id="btn-confirm-mail" onclick="confirmMailSent()">
<i class="fa fa-check mr-1"></i>Confirm &amp; Mark as Mail Sent
</button>
</div>
</div>
</div>
</div>
<!-- File Preview Modal (for settlement images) -->
<div class="modal fade" id="fileModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">File Preview</h5>
<button type="button" class="close" data-dismiss="modal"><span>&times;</span></button>
</div>
<div class="modal-body">
<embed id="filePreview" src="" width="100%" height="600px">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<footer th:replace="~{fragments/footer2 :: footer}"></footer>
</div>
<!-- END Page Container -->
<div th:replace="~{fragments/resetpassword :: div}"></div>
<script th:replace="~{fragments/loginscript :: script}"></script>
<script>
// ─────────────────────────────────────────────────────────────────────
// DataTable initialisation & Tab Switch Handlers
// ─────────────────────────────────────────────────────────────────────
$(document).ready(function () {
var dtButtons = [
{ extend: 'pageLength', className: 'btn btn-primary' },
{ extend: 'copyHtml5', text: 'Copy', className: 'btn btn-primary' },
{ extend: 'excelHtml5', text: 'Excel', className: 'btn btn-primary' },
{ extend: 'csvHtml5', text: 'CSV', className: 'btn btn-primary' },
{ extend: 'pdfHtml5', text: 'PDF', className: 'btn btn-primary' }
];
var dtOpts = {
dom: 'Bftip',
columnDefs: [{ targets: 'no-sort', orderable: false }],
lengthMenu: [[50, 100, 200, 500, -1], ['50 rows', '100 rows', '200 rows', '500 rows', 'Show all']],
buttons: dtButtons,
responsive: true,
searching: true,
autoWidth: false
};
// Initialize DataTables
$('#tbl-sixmonth').DataTable(dtOpts);
$('#tbl-cancelled').DataTable(dtOpts);
$('#tbl-rejected').DataTable(dtOpts);
$('#tbl-mailsent').DataTable(dtOpts);
// Explicit click handler to guarantee tab activation
$('#sixMonthTab a').on('click', function (e) {
e.preventDefault();
$(this).tab('show');
});
// Recalculate columns and responsive layout whenever any tab is shown
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
var targetTab = $(e.target).attr('href');
if (targetTab && $.fn.dataTable) {
try {
$(targetTab).find('table').each(function () {
if ($.fn.dataTable.isDataTable(this)) {
$(this).DataTable().columns.adjust().responsive.recalc();
}
});
} catch (err) {
console.log('Error adjusting table columns on tab switch:', err);
}
}
});
});
// ─────────────────────────────────────────────────────────────────────
// View Settlement Details (Tab 1 – uses /getSettlementList by settlementId)
// ─────────────────────────────────────────────────────────────────────
function viewSettlement(settlementId) {
$.ajax({
type: 'GET',
url: '/communityhall/api/officer/getSettlementList',
data: { settlementsid: settlementId },
success: function (data) {
populateSettlementModal(data);
$('#settlementModal').modal('show');
},
error: function () {
Swal.fire('Error', 'Failed to fetch settlement details.', 'error');
}
});
}
function populateSettlementModal(d) {
var html = '<div class="col-12">';
html += '<table class="table table-sm table-bordered">';
html += '<tr><th colspan="4" style="background:#f2f2f2;">User Details</th></tr>';
html += '<tr><th style="font-weight:normal">User Name:</th><td>' + (d.users ? d.users.name : '') + '</td>';
html += '<th style="font-weight:normal">Mobile No:</th><td>' + (d.users ? d.users.mobileNo : '') + '</td></tr>';
html += '<tr><th style="font-weight:normal">User Type:</th><td colspan="3">' + (d.users ? d.users.usertype : '') + '</td></tr>';
html += '<tr><th colspan="4" style="background:#f2f2f2;">Hall Details</th></tr>';
html += '<tr><th style="font-weight:normal">Hall Name:</th><td colspan="3">' + (d.hallDetails ? d.hallDetails.hallName : '') + '</td></tr>';
html += '<tr><th colspan="4" style="background:#f2f2f2;">Booking Details (ID: ' + d.bookingId + ')</th></tr>';
html += '<tr><th style="font-weight:normal">Booking Date:</th><td>' + d.bookingDate + '</td>';
html += '<th style="font-weight:normal">Deposit Amount:</th><td>₹ ' + parseFloat(d.depositAmount).toFixed(2) + '</td></tr>';
html += '<tr><th style="font-weight:normal">Start Date:</th><td>' + d.startDate + '</td>';
html += '<th style="font-weight:normal">End Date:</th><td>' + d.endDate + '</td></tr>';
// Settlement
if (d.settlement) {
html += '<tr><th colspan="4" style="background:#f2f2f2;">Settlement Details</th></tr>';
html += '<tr><th style="font-weight:normal">Refunded Amount:</th><td>₹ ' + parseFloat(d.settlement.refundedAmount || 0).toFixed(2) + '</td>';
html += '<th style="font-weight:normal">Damage Amount:</th><td>₹ ' + parseFloat(d.settlement.damageAmount || 0).toFixed(2) + '</td></tr>';
} else {
html += '<tr><td colspan="4" class="text-danger text-center font-italic">Settlement Not Initiated</td></tr>';
}
html += '</table></div>';
$('#settlementModalBody').html(html);
}
// ─────────────────────────────────────────────────────────────────────
// View Booking Details (Tab 2 & 3 – uses /getBookingDetails by bookingId)
// ─────────────────────────────────────────────────────────────────────
function viewBookingDetails(bookingId) {
if (!bookingId || bookingId === 0) {
Swal.fire('Warning', 'Invalid Booking ID.', 'warning');
return;
}
$.ajax({
type: 'GET',
url: '/communityhall/api/officer/getBookingDetails',
data: { bookingsId: bookingId },
success: function (data) {
populateBookingModal(data);
$('#bookingModal').modal('show');
},
error: function () {
Swal.fire('Error', 'Failed to fetch booking details.', 'error');
}
});
}
function populateBookingModal(d) {
var html = '<div class="col-12">';
html += '<table class="table table-sm table-bordered">';
html += '<tr><th colspan="4" style="background:#f2f2f2;">User Details</th></tr>';
html += '<tr><th style="font-weight:normal">User Name:</th><td>' + (d.users ? d.users.name : '') + '</td>';
html += '<th style="font-weight:normal">Mobile No:</th><td>' + (d.users ? d.users.mobileNo : '') + '</td></tr>';
html += '<tr><th style="font-weight:normal">User Type:</th><td colspan="3">' + (d.users ? d.users.usertype : '') + '</td></tr>';
html += '<tr><th colspan="4" style="background:#f2f2f2;">Hall Details</th></tr>';
html += '<tr><th style="font-weight:normal">Hall Name:</th><td colspan="3">' + (d.hallDetails ? d.hallDetails.hallName : '') + '</td></tr>';
html += '<tr><th colspan="4" style="background:#f2f2f2;">Booking Details (ID: ' + d.bookingId + ')</th></tr>';
html += '<tr><th style="font-weight:normal">Booking Date:</th><td>' + d.bookingDate + '</td>';
html += '<th style="font-weight:normal">Booking Status:</th><td>' + d.bookingStatus + '</td></tr>';
html += '<tr><th style="font-weight:normal">Start Date:</th><td>' + d.startDate + '</td>';
html += '<th style="font-weight:normal">End Date:</th><td>' + d.endDate + '</td></tr>';
html += '<tr><th style="font-weight:normal">Deposit Amount:</th><td>₹ ' + parseFloat(d.depositAmount).toFixed(2) + '</td>';
html += '<th style="font-weight:normal">Total Amount:</th><td>₹ ' + parseFloat(d.amountReceived).toFixed(2) + '</td></tr>';
// Payment
if (d.payments) {
html += '<tr><th colspan="4" style="background:#f2f2f2;">Payment Details</th></tr>';
html += '<tr><th style="font-weight:normal">Transaction ID:</th><td colspan="3">' + d.payments.transactionId + '</td></tr>';
html += '<tr><th style="font-weight:normal">Amount Received:</th><td>₹ ' + d.payments.amountReceived + '</td>';
html += '<th style="font-weight:normal">Payment Status:</th><td>' + d.payments.paymentStatus + '</td></tr>';
}
html += '</table></div>';
$('#bookingModalBody').html(html);
}
// ─────────────────────────────────────────────────────────────────────
// Send Mail Flow
// ─────────────────────────────────────────────────────────────────────
function openSendMail(bookingId, bookingStatus, transactionId, tpslId, transactionDate, refundAmount) {
Swal.fire({
title: 'Send Refund Follow-up Mail?',
html: 'This will send a refund status request mail for Booking ID <strong>' + bookingId + '</strong>.<br>Do you want to proceed?',
icon: 'question',
showCancelButton: true,
confirmButtonText: 'Yes, Show Draft',
cancelButtonText: 'Cancel',
confirmButtonColor: '#1a73e8'
}).then(function (result) {
if (result.isConfirmed) {
showDraftMail(bookingId, bookingStatus, transactionId, tpslId, transactionDate, refundAmount);
}
});
}
function showDraftMail(bookingId, bookingStatus, transactionId, tpslId, transactionDate, refundAmount) {
document.getElementById('dm_bookingId').value = bookingId;
document.getElementById('dm_bookingStatus').value = bookingStatus;
document.getElementById('dm_transactionId').value = transactionId || '';
document.getElementById('dm_tpslId').value = tpslId || '';
document.getElementById('dm_refundAmount').value = refundAmount || 0;
var amt = parseFloat(refundAmount || 0).toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
var body = 'Hi,\n\n';
body += 'Kindly update refund status for the foresaid transaction made for Community Hall Booking.\n\n';
body += 'Transaction Details:\n\n';
body += ' Transaction ID : ' + (transactionId || 'N/A') + '\n';
body += ' TPSL ID : ' + (tpslId || 'N/A') + '\n';
body += ' Transaction Date : ' + (transactionDate || 'N/A') + '\n';
body += ' Refund Amount : ₹ ' + amt + '\n\n';
body += 'If refund was not initiated, kindly initiate the refund and update refund status at the earliest. ';
body += 'Make sure that no duplicate refund was processed against this transaction.\n\n';
body += 'Regards,\n';
body += 'Community Hall Support\n';
body += 'Greater Chennai Corporation';
document.getElementById('draftMailBody').textContent = body;
$('#draftMailModal').modal('show');
}
function confirmMailSent() {
var bookingId = document.getElementById('dm_bookingId').value;
var bookingStatus = document.getElementById('dm_bookingStatus').value;
var transactionId = document.getElementById('dm_transactionId').value;
var tpslId = document.getElementById('dm_tpslId').value;
var refundAmount = document.getElementById('dm_refundAmount').value;
var mailTo = "pgsupport@mail.in.worldline-solutions.com,ranjithkumar@federal.bank.in,megha.mattamana@federal.bank.in";
var mailCc = "arohqcc@gmail.com,it@chennaicorporation.gov.in";
var mailSubject = "Refund Status Update Request – Community Hall Booking";
var mailBody = document.getElementById('draftMailBody').textContent;
var mailtoLink = "mailto:" + mailTo + "?cc=" + mailCc + "&subject=" + encodeURIComponent(mailSubject) + "&body=" + encodeURIComponent(mailBody);
window.location.href = mailtoLink;
document.getElementById('btn-confirm-mail').disabled = true;
$.ajax({
type: 'POST',
url: '/communityhall/headquarters/sixmonthold-transactions/markMailSent',
data: {
bookingId: bookingId,
bookingStatus: bookingStatus,
transactionId: transactionId,
tpslId: tpslId,
refundAmount: refundAmount
},
success: function (resp) {
$('#draftMailModal').modal('hide');
if (resp.status === 'success') {
Swal.fire({
icon: 'success',
title: 'Mail Recorded!',
text: 'Booking ID ' + bookingId + ' has been moved to "Mail Sent Bookings" tab.',
confirmButtonColor: '#1a73e8'
}).then(function () {
location.reload();
});
} else {
Swal.fire('Error', resp.message || 'An error occurred.', 'error');
document.getElementById('btn-confirm-mail').disabled = false;
}
},
error: function () {
Swal.fire('Error', 'Failed to mark mail as sent. Please try again.', 'error');
document.getElementById('btn-confirm-mail').disabled = false;
}
});
}
</script>
</body>
</html>

91
src/main/resources/templates/admin/bookingwaiting.html

@ -24,6 +24,7 @@
width: 100% !important;
}
</style>
<body>
<!-- Page Container -->
<div id="page-container"
@ -47,7 +48,8 @@
<div class="block-content p-0">
<div class="p-sm-4 p-0">
<div class="table-responsive">
<table class="table table-bordered table-striped table-vcenter js-dataTable-responsive" id="bookingapprovedtable">
<table class="table table-bordered table-striped table-vcenter js-dataTable-responsive"
id="bookingapprovedtable">
<thead class="thead-light">
<tr>
<th class="text-center no-sort">S.No</th>
@ -292,7 +294,8 @@
</div>
<div class="row" id="reasondetails">
<div class="col-md-6 mb-2">
<label class="form-label">Reason type :<span class="text-danger">*</span></label>
<label class="form-label">Reason type :<span
class="text-danger">*</span></label>
<select class="form-control" id="reasontype">
<option value="0">Select Reason type</option>
<option value="1">Illegal</option>
@ -301,8 +304,10 @@
</div>
<div class="col-md-6 mb-2">
<label class="form-label">Reason:<span class="text-danger">*</span></label>
<textarea class="form-control " name="reason" id="reason" required style="height: 9px;"></textarea>
<div id="reasonValidationText" class="text-danger small mt-1" style="display:none">
<textarea class="form-control " name="reason" id="reason" required
style="height: 9px;"></textarea>
<div id="reasonValidationText" class="text-danger small mt-1"
style="display:none">
Reason is required.</div>
</div>
</div>
@ -322,7 +327,8 @@
</div>
<!-- End Modal User -->
<!-- Footer -->
<div class="modal fade" id="fileModal" tabindex="-1" role="dialog" aria-labelledby="fileModalLabel" aria-hidden="true">
<div class="modal fade" id="fileModal" tabindex="-1" role="dialog" aria-labelledby="fileModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
@ -455,6 +461,9 @@
function showReasonWithDocument(reasonData, list) {
var reasonDocumentData = reasonData.reasonDocumentMasterList;
var bookingDocumentsList = list.bookingDocumentsList;
console.log("reasonDocumentData;;;" + reasonDocumentData);
console.log("bookingDocumentsList;;;" + bookingDocumentsList);
const reasonFieldsContainer = $('#documents');
reasonFieldsContainer.empty();
// Create a responsive table container
@ -485,24 +494,67 @@
// Create the table body (tbody)
var tbody = $('<tbody>').appendTo(table);
// Iterate through the documents list and populate rows
for (var i = 0; i < bookingDocumentsList.length; i++) {
(function (index) {
var row = $('<tr>').appendTo(tbody);
$('<td>').text(index + 1).appendTo(row);
// Helper: find the latest uploaded doc for a given master document entry.
// If docs have a booking_label, group by label prefix (e.g. NOC_1/NOC_2 under "NOC").
// Otherwise, use offset-from-end positional matching so that when a rescheduled
// re-upload exists (more docs than master entries), the newest doc is shown.
function getDocsForMaster(masterIndex, docFieldName) {
// Try label-based grouping first (e.g. NOC_1, NOC_2 → grouped under "NOC")
var labelPrefix = docFieldName ? docFieldName.replace(/[^a-zA-Z0-9]/g, '_') : null;
var labeled = bookingDocumentsList.filter(function (doc) {
return doc.booking_label && labelPrefix &&
doc.booking_label.toUpperCase().startsWith(labelPrefix.toUpperCase());
});
if (labeled.length > 0) return labeled;
// Fallback: offset-from-end positional match.
// When extra docs exist (e.g. 2 NOC uploads for 1 NOC master row),
// this picks the latest upload instead of the original.
var extraCount = bookingDocumentsList.length - reasonDocumentData.length;
var adjustedIndex = masterIndex + (extraCount > 0 ? extraCount : 0);
return bookingDocumentsList[adjustedIndex] ? [bookingDocumentsList[adjustedIndex]] : [];
}
// Iterate over the master document list (one entry per required document type)
for (var i = 0; i < reasonDocumentData.length; i++) {
(function (masterIndex) {
var masterDoc = reasonDocumentData[masterIndex];
var matchedDocs = getDocsForMaster(masterIndex, masterDoc.docFieldName);
// Determine the text content for the second cell
var name = bookingDocumentsList[index].name ? bookingDocumentsList[index].name : ''; // Empty string if name is null or undefined
var fieldText = reasonDocumentData[index].fieldName;
var fullText = name ? fieldText + ': ' + name : fieldText; // Include colon only if name is not empty
var row = $('<tr>').appendTo(tbody);
$('<td>').text(masterIndex + 1).appendTo(row);
// Required Info cell (use name from first matched doc, if any)
var firstName = (matchedDocs.length > 0 && matchedDocs[0].name) ? matchedDocs[0].name : '';
var fullText = firstName ? masterDoc.fieldName + ': ' + firstName : masterDoc.fieldName;
$('<td>').text(fullText).appendTo(row);
// Create a link to view document image
var viewLink = $('<a>').attr('href', 'javascript:void(0)').text(reasonDocumentData[index].docFieldName).on('click', function () {
showDocumentImage(bookingDocumentsList[index].bookingDocUrl);
});
$('<td>').append(viewLink).appendTo(row);
// Document links cell — show all uploads for this master entry
var docLinksCell = $('<td>');
if (matchedDocs.length === 0) {
docLinksCell.text('Not uploaded');
} else if (matchedDocs.length === 1) {
// Single upload — show plain link with docFieldName label
(function (doc) {
var viewLink = $('<a>').attr('href', 'javascript:void(0)')
.text(masterDoc.docFieldName)
.on('click', function () { showDocumentImage(doc.bookingDocUrl); });
docLinksCell.append(viewLink);
})(matchedDocs[0]);
} else {
// Multiple uploads (e.g. NOC original + after reschedule) — show labeled links
var uploadLabels = ['Original', 'After Reschedule'];
for (var j = 0; j < matchedDocs.length; j++) {
(function (doc, uploadIndex) {
var label = uploadLabels[uploadIndex] || ('Upload ' + (uploadIndex + 1));
var viewLink = $('<a>').attr('href', 'javascript:void(0)')
.text(masterDoc.docFieldName + ' (' + label + ')')
.on('click', function () { showDocumentImage(doc.bookingDocUrl); });
if (uploadIndex > 0) docLinksCell.append($('<br>'));
docLinksCell.append(viewLink);
})(matchedDocs[j], j);
}
}
docLinksCell.appendTo(row);
})(i);
}
// Append table to the responsive container
@ -709,4 +761,5 @@
});
</script>
</body>
</html>

40
src/main/resources/templates/fragments/PaymentScript.html

@ -121,7 +121,27 @@
success: function (response) {
// console.log(response);
if (response.error) {
alert("please Contact Admin..")
if (response.slotOccupied) {
Swal.fire({
icon: 'warning',
title: 'Slot Already Occupied',
text: response.message,
confirmButtonText: 'OK',
confirmButtonColor: '#d33'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = "/communityhall/user/hallbookingform";
}
});
} else {
Swal.fire({
icon: 'error',
title: 'Error',
text: response.message ? response.message : 'Something went wrong. Please contact Admin.',
confirmButtonText: 'OK',
confirmButtonColor: '#d33'
});
}
} else {
txansactionId = response.txansactionId;
@ -167,7 +187,23 @@
success: function (response) {
// console.log(response);
if (response.error) {
alert("please Contact Admin..")
if (response.slotOccupied) {
Swal.fire({
icon: 'warning',
title: 'Slot Already Occupied',
text: response.message,
confirmButtonText: 'OK',
confirmButtonColor: '#d33'
});
} else {
Swal.fire({
icon: 'error',
title: 'Error',
text: response.message ? response.message : 'Something went wrong. Please contact Admin.',
confirmButtonText: 'OK',
confirmButtonColor: '#d33'
});
}
} else {
txansactionId = response.txansactionId;

2
src/main/resources/templates/fragments/headquartersMenu.html

@ -39,7 +39,7 @@
<li class="nav-main-item">
<a class="nav-main-link" href="/communityhall/headquarters/GccblockingNew">
<i class="nav-main-link-icon fa fa-location-arrow"></i>
<span class="nav-main-link-name">GCC Blocking (New)</span>
<span class="nav-main-link-name">GCC Blocking</span>
</a>
</li>
<li class="nav-main-item">

91
src/main/resources/templates/headquarters/bookingwaiting.html

@ -24,6 +24,7 @@
width: 100% !important;
}
</style>
<body>
<!-- Page Container -->
<div id="page-container"
@ -47,7 +48,8 @@
<div class="block-content p-0">
<div class="p-sm-4 p-0">
<div class="table-responsive">
<table class="table table-bordered table-striped table-vcenter js-dataTable-responsive" id="bookingapprovedtable">
<table class="table table-bordered table-striped table-vcenter js-dataTable-responsive"
id="bookingapprovedtable">
<thead class="thead-light">
<tr>
<th class="text-center no-sort">S.No</th>
@ -290,7 +292,8 @@
</div>
<div class="row" id="reasondetails">
<div class="col-md-6 mb-2">
<label class="form-label">Reason type :<span class="text-danger">*</span></label>
<label class="form-label">Reason type :<span
class="text-danger">*</span></label>
<select class="form-control" id="reasontype">
<option value="0">Select Reason type</option>
<option value="1">Illegal</option>
@ -299,8 +302,10 @@
</div>
<div class="col-md-6 mb-2">
<label class="form-label">Reason:<span class="text-danger">*</span></label>
<textarea class="form-control " name="reason" id="reason" required style="height: 9px;"></textarea>
<div id="reasonValidationText" class="text-danger small mt-1" style="display:none">
<textarea class="form-control " name="reason" id="reason" required
style="height: 9px;"></textarea>
<div id="reasonValidationText" class="text-danger small mt-1"
style="display:none">
Reason is required.</div>
</div>
</div>
@ -320,7 +325,8 @@
</div>
<!-- End Modal User -->
<!-- Footer -->
<div class="modal fade" id="fileModal" tabindex="-1" role="dialog" aria-labelledby="fileModalLabel" aria-hidden="true">
<div class="modal fade" id="fileModal" tabindex="-1" role="dialog" aria-labelledby="fileModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
@ -507,6 +513,9 @@
function showReasonWithDocument(reasonData, list) {
var reasonDocumentData = reasonData.reasonDocumentMasterList;
var bookingDocumentsList = list.bookingDocumentsList;
console.log("reasonDocumentData;;;" + reasonDocumentData);
console.log("bookingDocumentsList;;;" + bookingDocumentsList);
const reasonFieldsContainer = $('#documents');
reasonFieldsContainer.empty();
// Create a responsive table container
@ -537,24 +546,67 @@
// Create the table body (tbody)
var tbody = $('<tbody>').appendTo(table);
// Iterate through the documents list and populate rows
for (var i = 0; i < bookingDocumentsList.length; i++) {
(function (index) {
var row = $('<tr>').appendTo(tbody);
$('<td>').text(index + 1).appendTo(row);
// Helper: find the latest uploaded doc for a given master document entry.
// If docs have a booking_label, group by label prefix (e.g. NOC_1/NOC_2 under "NOC").
// Otherwise, use offset-from-end positional matching so that when a rescheduled
// re-upload exists (more docs than master entries), the newest doc is shown.
function getDocsForMaster(masterIndex, docFieldName) {
// Try label-based grouping first (e.g. NOC_1, NOC_2 → grouped under "NOC")
var labelPrefix = docFieldName ? docFieldName.replace(/[^a-zA-Z0-9]/g, '_') : null;
var labeled = bookingDocumentsList.filter(function (doc) {
return doc.booking_label && labelPrefix &&
doc.booking_label.toUpperCase().startsWith(labelPrefix.toUpperCase());
});
if (labeled.length > 0) return labeled;
// Fallback: offset-from-end positional match.
// When extra docs exist (e.g. 2 NOC uploads for 1 NOC master row),
// this picks the latest upload instead of the original.
var extraCount = bookingDocumentsList.length - reasonDocumentData.length;
var adjustedIndex = masterIndex + (extraCount > 0 ? extraCount : 0);
return bookingDocumentsList[adjustedIndex] ? [bookingDocumentsList[adjustedIndex]] : [];
}
// Iterate over the master document list (one entry per required document type)
for (var i = 0; i < reasonDocumentData.length; i++) {
(function (masterIndex) {
var masterDoc = reasonDocumentData[masterIndex];
var matchedDocs = getDocsForMaster(masterIndex, masterDoc.docFieldName);
// Determine the text content for the second cell
var name = bookingDocumentsList[index].name ? bookingDocumentsList[index].name : ''; // Empty string if name is null or undefined
var fieldText = reasonDocumentData[index].fieldName;
var fullText = name ? fieldText + ': ' + name : fieldText; // Include colon only if name is not empty
var row = $('<tr>').appendTo(tbody);
$('<td>').text(masterIndex + 1).appendTo(row);
// Required Info cell (use name from first matched doc, if any)
var firstName = (matchedDocs.length > 0 && matchedDocs[0].name) ? matchedDocs[0].name : '';
var fullText = firstName ? masterDoc.fieldName + ': ' + firstName : masterDoc.fieldName;
$('<td>').text(fullText).appendTo(row);
// Create a link to view document image
var viewLink = $('<a>').attr('href', 'javascript:void(0)').text(reasonDocumentData[index].docFieldName).on('click', function () {
showDocumentImage(bookingDocumentsList[index].bookingDocUrl);
});
$('<td>').append(viewLink).appendTo(row);
// Document links cell — show all uploads for this master entry
var docLinksCell = $('<td>');
if (matchedDocs.length === 0) {
docLinksCell.text('Not uploaded');
} else if (matchedDocs.length === 1) {
// Single upload — show plain link with docFieldName label
(function (doc) {
var viewLink = $('<a>').attr('href', 'javascript:void(0)')
.text(masterDoc.docFieldName)
.on('click', function () { showDocumentImage(doc.bookingDocUrl); });
docLinksCell.append(viewLink);
})(matchedDocs[0]);
} else {
// Multiple uploads (e.g. NOC original + after reschedule) — show labeled links
var uploadLabels = ['Original', 'After Reschedule'];
for (var j = 0; j < matchedDocs.length; j++) {
(function (doc, uploadIndex) {
var label = uploadLabels[uploadIndex] || ('Upload ' + (uploadIndex + 1));
var viewLink = $('<a>').attr('href', 'javascript:void(0)')
.text(masterDoc.docFieldName + ' (' + label + ')')
.on('click', function () { showDocumentImage(doc.bookingDocUrl); });
if (uploadIndex > 0) docLinksCell.append($('<br>'));
docLinksCell.append(viewLink);
})(matchedDocs[j], j);
}
}
docLinksCell.appendTo(row);
})(i);
}
// Append table to the responsive container
@ -761,4 +813,5 @@
});
</script>
</body>
</html>

4
src/main/resources/templates/headquarters/reports.html

@ -947,7 +947,7 @@
</div>
</div>
<div class="row col-md-12 col-lg-12 col-sm-12" id="ebdetails"
style="display:none;margin-left: 0px;margin-top: -10px">
style="display:none;margin-left: 0px;">
<div class="card-body">
<table>
<tr>
@ -1066,7 +1066,7 @@
</div>
</div>
<div class="row col-md-12 col-lg-12 col-sm-12" id="refundamountDetails"
style="display:none;margin-left: 0px;margin-top: -49px">
style="display:none;margin-left: 0px;">
<div class="card-body">
<table>
<tr>

64
src/main/resources/templates/headquarters/sixmonthold-transactions.html

@ -544,10 +544,10 @@
</button><br><br>
<!-- Update Refund Details: opens refund update modal (calls /updateApprovedSettlementStatus) -->
<button class="btn-sendmail btn-update-refund"
th:if="${row['booking_status'] != 'COMPLETED'}"
th:data-booking-id="${row['booking_id']}"
th:data-booking-status="${row['booking_status']}"
th:data-settlement-id="${row['settlement_id']}"
th:disabled="${row['booking_status'] == 'COMPLETED'}">
th:data-settlement-id="${row['settlement_id']}">
Update Refund Details
</button>
</td>
@ -564,57 +564,6 @@
</main>
<!-- END Main Container -->
<!-- ══════════════════════════════════════════════════════════════════
MODAL – Settlement View Details (Tab 1 with settlement)
══════════════════════════════════════════════════════════════════ -->
<!-- <div class="modal fade" id="settlementModal" data-backdrop="static" tabindex="-1" role="dialog"
aria-labelledby="settlementModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="block block-rounded block-themed block-transparent mb-0">
<div class="block-header bg-primary-dark">
<h3 class="block-title" id="settlementModalLabel">Settlement Information</h3>
<div class="block-options">
<button type="button" class="btn-block-option" data-dismiss="modal" aria-label="Close">
<i class="fa fa-fw fa-times"></i>
</button>
</div>
</div>
<div class="block-content row p-3" id="settlementModalBody">
</div>
<div class="block-content block-content-full text-right bg-body">
<button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="bookingModal" data-backdrop="static" tabindex="-1" role="dialog"
aria-labelledby="bookingModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="block block-rounded block-themed block-transparent mb-0">
<div class="block-header bg-primary-dark">
<h3 class="block-title" id="bookingModalLabel">Booking Information</h3>
<div class="block-options">
<button type="button" class="btn-block-option" data-dismiss="modal" aria-label="Close">
<i class="fa fa-fw fa-times"></i>
</button>
</div>
</div>
<div class="block-content row p-3" id="bookingModalBody">
</div>
<div class="block-content block-content-full text-right bg-body">
<button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div> -->
<div class="modal fade backdrop" id="initiateSettlementForm" data-backdrop="static" tabindex="-1" role="dialog"
aria-labelledby="staticBackdropLabel" aria-hidden="true">
@ -933,7 +882,7 @@
<select class="form-control" id="ur_status">
<option value="">-- Select Status --</option>
<option value="COMPLETED">COMPLETED</option>
<option value="CLOSED">CLOSED</option>
<!-- <option value="CLOSED">CLOSED</option> -->
</select>
</div>
<!-- Refund Date -->
@ -941,14 +890,16 @@
<label for="ur_refundDate">
<strong>Refund Date <span class="text-danger">*</span></strong>
</label>
<input type="date" class="form-control" id="ur_refundDate" required>
<input type="date" class="form-control" id="ur_refundDate" onkeydown="return false;"
onpaste="return false;" autocomplete="off" onclick="this.showPicker();" required>
</div>
<!-- ARN Number -->
<div class="form-group">
<label for="ur_arnNumber"><strong>ARN Number <span
class="text-danger">*</span></strong></label>
<input type="text" class="form-control" id="ur_arnNumber" placeholder="Enter ARN Number..."
maxlength="15" minlength="12" pattern="\d{12,15}" inputmode="numeric" required>
maxlength="15" minlength="12" pattern="[0-9]{12,15}" inputmode="numeric"
oninput="this.value = this.value.replace(/\D/g, '')" required>
</div>
<!-- Comments -->
<div class="form-group">
@ -1560,6 +1511,7 @@
// submitRefundUpdate: posts to /updateRefundDetails with the correct ID depending on booking status
function submitRefundUpdate() {
var today = new Date().toISOString().split('T')[0];
var settlementId = document.getElementById('ur_settlementId').value;
var status = document.getElementById('ur_status').value;
var refundDate = document.getElementById('ur_refundDate').value;

18
src/main/resources/templates/user/hallbookingform.html

@ -1000,6 +1000,18 @@
pointer-events: auto !important;
}
td.highlight-violet.ui-state-disabled {
opacity: 1 !important;
}
td.highlight-yellow.ui-state-disabled {
opacity: 1 !important;
}
td.highlight-pink.ui-state-disabled {
opacity: 1 !important;
}
/* css fror toast */
/* Toast styling */
#toast {
@ -3337,11 +3349,11 @@
function handleBookingStatus(bookingStatus, defaultMessage) {
if (bookingStatus[2] && bookingStatus[0] && !bookingStatus[1]) {
return [true, "highlight-yellow disabled", "GCC Blocked"];
return [false, "highlight-yellow disabled", "GCC Blocked"];
} else if (bookingStatus[2] && bookingStatus[1] && !bookingStatus[0]) {
return [true, "highlight-violet disabled", "GCC Blocked"];
return [false, "highlight-violet disabled", "GCC Blocked"];
} else if (bookingStatus[2] && bookingStatus[1] && bookingStatus[0] && bookingStatus[3] != 'GCC_BLOCKED' && bookingStatus[4] != 'GCC_BLOCKED') {
return [true, "highlight-pink disabled", "GCC Blocked"];
return [false, "highlight-pink disabled", "GCC Blocked"];
} else if (bookingStatus[2] && bookingStatus[1] && bookingStatus[0] && bookingStatus[3] == 'GCC_BLOCKED' && bookingStatus[4] == 'GCC_BLOCKED') {
return [false, "highlight-blue disabled", "GCC Blocked"];
} else if (bookingStatus[2]) {

155
src/main/resources/templates/user/viewhistory.html

@ -549,6 +549,31 @@
border: 1px solid #ccc;
border-radius: 5px;
}
td.highlight-blue.ui-state-disabled {
opacity: 1 !important;
}
td.highlight-blue.ui-state-disabled .ui-state-default,
td.highlight-blue.ui-state-disabled a,
td.highlight-blue.ui-state-disabled span {
background: blue !important;
color: #fff !important;
cursor: not-allowed !important;
pointer-events: auto !important;
}
td.highlight-violet.ui-state-disabled {
opacity: 1 !important;
}
td.highlight-yellow.ui-state-disabled {
opacity: 1 !important;
}
td.highlight-pink.ui-state-disabled {
opacity: 1 !important;
}
</style>
<body>
@ -1456,17 +1481,19 @@
<div class="col">
<input type="hidden" id="daysDiff">
<label for="startingSlot" class="form-label">Starting Slot:</label>
<input type="text" class="form-control" id="startingSlotText"
name="startingSlot" readonly>
<input type="hidden" class="form-control" id="startingSlot"
name="startingSlot" required>
<select class="form-control" id="startingSlot" name="startingSlot">
<option value="1">Morning (6:00 AM)</option>
<option value="2">Afternoon (2:00 PM)</option>
</select>
</div>
<div class="col">
<label for="endingSlot" class="form-label">Ending Slot:</label>
<input type="text" class="form-control" id="endingSlotText"
name="endDateInput" readonly>
<input type="hidden" class="form-control" id="endingSlot"
name="endDateInput" readonly>
<select class="form-control" id="endingSlot" name="endingSlot" disabled>
<option value="1">Afternoon (2:00 PM)</option>
<option value="2">Evening (10:00 PM)</option>
</select>
<!-- mirrors endingSlot for form submission since disabled fields are excluded -->
<input type="hidden" id="endingSlotHidden" name="endingSlot">
</div>
</div>
<div class="row" style="margin-top: 39px;">
@ -2382,14 +2409,15 @@
document.getElementById("startDateInput").value = startDate;
document.getElementById("endDateInput").value = endDate;
document.getElementById("noOfDaysInput").value = noOfDays;
document.getElementById("startingSlot").value = startingSlot;
document.getElementById("endingSlot").value = endingSlot;
document.getElementById("startingSlot").value = String(startingSlot);
document.getElementById("endingSlot").value = String(endingSlot);
document.getElementById("endingSlotHidden").value = String(endingSlot);
document.getElementById("daysDiff").value = daysDiff;
// Display slot text in the modal
document.getElementById("startDatetext").value = startDate;
document.getElementById("startingSlotText").value = getSlotText(startingSlot);
document.getElementById("endingSlotText").value = getSlotText(endingSlot);
// document.getElementById("startingSlotText").value = getSlotText(startingSlot);
// document.getElementById("endingSlotText").value = getSlotText(endingSlot);
// Store booking details for OTP verification
rescheduleBookingId = bookingId;
@ -2503,9 +2531,9 @@
$("#startDateInput").on("change", function () {
var selectedDate = $(this).val();
var noOfDays = document.getElementById('noOfDaysInput').value;
// var noOfDays = document.getElementById('noOfDaysInput').value;
var startingSlot = document.getElementById("startingSlot").value;
var endingSlot = document.getElementById("endingSlot").value;
var endingSlot = document.getElementById("endingSlotHidden").value;
var noofdays = document.getElementById("noOfDaysInput").value;
updateEndDate(selectedDate, noofdays, startingSlot, endingSlot);
});
@ -2540,15 +2568,15 @@
function handleBookingStatus(bookingStatus, defaultMessage) {
if (bookingStatus[2] && bookingStatus[0] && !bookingStatus[1]) {
return [true, "highlight-yellow disabled", "GCC Blocked"];
return [false, "highlight-yellow disabled", "GCC Blocked"];
} else if (bookingStatus[2] && bookingStatus[1] && !bookingStatus[0]) {
return [true, "highlight-violet disabled", "GCC Blocked"];
return [false, "highlight-violet disabled", "GCC Blocked"];
} else if (bookingStatus[2] && bookingStatus[1] && bookingStatus[0] && bookingStatus[3] != 'GCC_BLOCKED' && bookingStatus[4] != 'GCC_BLOCKED') {
return [true, "highlight-pink disabled", "GCC Blocked"];
return [false, "highlight-pink disabled", "GCC Blocked"];
} else if (bookingStatus[2] && bookingStatus[1] && bookingStatus[0] && bookingStatus[3] == 'GCC_BLOCKED' && bookingStatus[4] == 'GCC_BLOCKED') {
return [true, "highlight-blue disabled", "GCC Blocked"];
return [false, "highlight-blue disabled", "GCC Blocked"];
} else if (bookingStatus[2]) {
return [true, "highlight-blue disabled", "GCC Blocked"];
return [false, "highlight-blue disabled", "GCC Blocked"];
} else if (bookingStatus[0] && bookingStatus[1]) {
return [true, "highlight-pink disabled", "Slot Occupied"];
} else if (bookingStatus[0] && !bookingStatus[1]) {
@ -2936,7 +2964,7 @@
// --- Slot availability check for today's date ---
var startDate = document.getElementById("startDateInput").value;
var startingSlot = document.getElementById("startingSlot").value;
var endingSlot = document.getElementById("endingSlot").value;
var endingSlot = document.getElementById("endingSlotHidden").value;
var todayDateStr = $("#serverDate").val();
var currentHour = new Date().getHours();
@ -3149,7 +3177,9 @@
console.log('Reschedule data:', {
bookingId: rescheduleBookingId,
startDate: rescheduleStartDate,
endDate: rescheduleEndDate
endDate: rescheduleEndDate,
startingSlot: rescheduleStartingSlot,
endingSlot: rescheduleEndingSlot
});
$.ajax({
@ -3158,7 +3188,9 @@
data: {
bookingId: rescheduleBookingId,
startDate: rescheduleStartDate,
endDate: rescheduleEndDate
endDate: rescheduleEndDate,
startingSlot: rescheduleStartingSlot,
endingSlot: rescheduleEndingSlot
},
success: function (response) {
Swal.fire({
@ -3210,7 +3242,8 @@
var endDate = document.getElementById("endDateInput").value;
var originalStartDate = document.getElementById("startDatetext").value;
var startingSlot = document.getElementById("startingSlot").value;
var endingSlot = document.getElementById("endingSlot").value;
// var endingSlot = document.getElementById("endingSlot").value;
var endingSlot = document.getElementById("endingSlotHidden").value;
// Get today's date from server
var todayDateStr = $("#serverDate").val();
@ -3228,15 +3261,15 @@
});
// Check if the rescheduled start date is the same as the original booked start date
if (startDate === originalStartDate) {
Swal.fire({
icon: 'warning',
title: 'Warning',
text: 'Your Rescheduled Start Date is the same as Your booking Start Date. Please change the date.',
showConfirmButton: true
});
return;
}
// if (startDate === originalStartDate) {
// Swal.fire({
// icon: 'warning',
// title: 'Warning',
// text: 'Your Rescheduled Start Date is the same as Your booking Start Date. Please change the date.',
// showConfirmButton: true
// });
// return;
// }
if (!endDate) {
Swal.fire({
icon: 'error',
@ -3286,11 +3319,15 @@
// Store the validated dates
rescheduleStartDate = startDate;
rescheduleEndDate = endDate;
rescheduleStartingSlot = document.getElementById('startingSlot').value;
rescheduleEndingSlot = document.getElementById('endingSlotHidden').value;
// Debug: Log the final dates being sent
console.log('Final reschedule dates:', {
startDate: rescheduleStartDate,
endDate: rescheduleEndDate,
startingSlot: rescheduleStartingSlot,
endingSlot: rescheduleEndingSlot,
bookingId: rescheduleBookingId
});
proceedWithReschedule();
@ -3452,6 +3489,60 @@
}
}
// ── Slot helper ──────────────────────────────────────────────────────
// Ending slot is deterministic: given (startSlot + noOfDays) there is
// exactly one valid ending slot. The user can only change Starting Slot;
// Ending Slot auto-fixes based on this table:
//
// noOfDays | start=1(Morning) → end | start=2(Afternoon) → end
// ---------|------------------------|-------------------------
// 0.5 | 1 (same slot, half-day) | 2 (same slot, half-day)
// 1 | 2 (6AM→10PM, full day) | 1 (2PM→next day 2PM)
// 1.5 | 1 (6AM→next day 2PM) | 2 (2PM→next day 10PM)
// 2 | 2 (6AM→day+1 10PM) | ❌ not allowed
function computeEndingSlot(startSlot, noOfDays) {
startSlot = String(startSlot);
noOfDays = parseFloat(noOfDays);
if (noOfDays === 0.5) return startSlot; // same slot, half-day
if (noOfDays === 1) return startSlot === "1" ? "2" : "1"; // flip: full-day
if (noOfDays === 1.5) return startSlot; // same slot, 1.5 days
if (noOfDays === 2) return startSlot === "1" ? "2" : null; // only morning valid for 2-day
return null;
}
// When user changes Starting Slot → auto-fix Ending Slot, re-validate end date
document.getElementById("startingSlot").addEventListener("change", function () {
var startSlot = this.value;
var noOfDays = parseFloat(document.getElementById("noOfDaysInput").value);
var endSlot = computeEndingSlot(startSlot, noOfDays);
// Guard: Afternoon start is not valid for 2-day booking
if (endSlot === null) {
Swal.fire({
icon: 'warning',
title: 'Slot Not Allowed',
text: 'Afternoon start is not supported for a ' + noOfDays + '-day booking. Reverting to the original slot.',
showConfirmButton: true
});
this.value = String(rescheduleStartingSlot);
return;
}
// Auto-fix the (disabled) ending slot display and its hidden mirror
document.getElementById("endingSlot").value = endSlot;
document.getElementById("endingSlotHidden").value = endSlot;
// Clear the computed end date — user must re-pick or it will re-compute
document.getElementById("endDateInput").value = "";
// If a start date is already selected, re-compute end date immediately
var startDate = document.getElementById("startDateInput").value;
if (startDate) {
updateEndDate(startDate, noOfDays, startSlot, endSlot);
}
});
// OTP input navigation for reschedule modal
$('.otp-input').on('keyup', function (e) {
var $this = $(this);

3530
src/main/resources/templates/user/viewhistory_old.html
File diff suppressed because it is too large
View File

3538
src/main/resources/templates/user/viewhistory_reschedulelogic.html
File diff suppressed because it is too large
View File

Loading…
Cancel
Save