Subversion Repositories SmartDukaan

Rev

Rev 35458 | Rev 35654 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
32916 amit.gupta 1
package com.spice.profitmandi.web.controller;
2
 
35624 ranu 3
import com.fasterxml.jackson.databind.ObjectMapper;
33715 ranu 4
import com.razorpay.Utils;
33672 ranu 5
import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
33581 ranu 6
import com.spice.profitmandi.common.web.util.ResponseSender;
33715 ranu 7
import com.spice.profitmandi.dao.entity.fofo.Customer;
8
import com.spice.profitmandi.dao.entity.fofo.FofoOrder;
33672 ranu 9
import com.spice.profitmandi.dao.entity.fofo.UpsellRazorpayPaymentStatus;
33595 ranu 10
import com.spice.profitmandi.dao.repository.cs.AgentRecordingRepository;
33715 ranu 11
import com.spice.profitmandi.dao.repository.fofo.CustomerRepository;
12
import com.spice.profitmandi.dao.repository.fofo.FofoOrderRepository;
33672 ranu 13
import com.spice.profitmandi.dao.repository.fofo.UpsellRazorpayPaymentStatusRepository;
34481 ranu 14
import com.spice.profitmandi.service.integrations.kommuno.RecordingService;
32929 amit.gupta 15
import com.spice.profitmandi.service.integrations.smartping.SmartPingService;
16
import com.spice.profitmandi.service.integrations.smartping.model.CallDetailModel;
34481 ranu 17
import com.spice.profitmandi.service.integrations.smartping.model.PushCallLogModel;
32916 amit.gupta 18
import com.spice.profitmandi.web.util.MVCResponseSender;
19
import org.apache.logging.log4j.LogManager;
20
import org.apache.logging.log4j.Logger;
33715 ranu 21
import org.json.JSONObject;
32916 amit.gupta 22
import org.springframework.beans.factory.annotation.Autowired;
33672 ranu 23
import org.springframework.beans.factory.annotation.Value;
24
import org.springframework.http.HttpStatus;
33581 ranu 25
import org.springframework.http.MediaType;
26
import org.springframework.http.ResponseEntity;
32916 amit.gupta 27
import org.springframework.stereotype.Controller;
35624 ranu 28
import org.springframework.transaction.annotation.Transactional;
32916 amit.gupta 29
import org.springframework.ui.Model;
33591 ranu 30
import org.springframework.web.bind.annotation.ModelAttribute;
34483 ranu 31
import org.springframework.web.bind.annotation.RequestBody;
32916 amit.gupta 32
import org.springframework.web.bind.annotation.RequestMapping;
33
import org.springframework.web.bind.annotation.RequestMethod;
34
 
35
import javax.servlet.http.HttpServletRequest;
36
 
37
@Controller
35458 amit 38
@Transactional(rollbackFor = Throwable.class)
32916 amit.gupta 39
public class WebHookController {
40
 
41
    @Autowired
42
    MVCResponseSender mvcResponseSender;
43
 
33581 ranu 44
    @Autowired
45
    private ResponseSender<?> responseSender;
46
 
33715 ranu 47
    @Autowired
48
    private FofoOrderRepository fofoOrderRepository;
49
 
50
    @Autowired
51
    private CustomerRepository customerRepository;
52
 
32916 amit.gupta 53
    private static final Logger LOGGER = LogManager.getLogger(WebHookController.class);
54
 
32919 amit.gupta 55
    @Autowired
32929 amit.gupta 56
    SmartPingService smartPingService;
32916 amit.gupta 57
 
33595 ranu 58
    @Autowired
34481 ranu 59
    RecordingService recordingService;
33602 ranu 60
 
61
    @Autowired
33595 ranu 62
    AgentRecordingRepository agentRecordingRepository;
63
 
35624 ranu 64
    /**
65
     * Knowlarity Click2Call Webhook - First Event (Call Report Handler).
66
     * <p>
67
     * This endpoint is called by Knowlarity when a click-to-call event is initiated or completed.
68
     * Knowlarity sends call detail data as form-urlencoded POST, which is mapped to {@link CallDetailModel}.
69
     * <p>
70
     * The incoming third-party data from Knowlarity may not always match our expected model fields.
71
     * If Knowlarity changes their payload structure or sends unexpected/null values,
72
     * errors can occur during binding or in {@link RecordingService#updateAgentRecording}.
73
     * <p>
74
     * URL: POST /click2call/report-handler
75
     * Content-Type: application/x-www-form-urlencoded
76
     * Third-party: Knowlarity
77
     */
33590 ranu 78
    @RequestMapping(value = "/click2call/report-handler", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
33591 ranu 79
    public ResponseEntity<?> click2callReportHandlerPost(HttpServletRequest request, Model model, @ModelAttribute CallDetailModel callDetail) throws Exception {
35624 ranu 80
        // Log raw parameters from Knowlarity before processing, so we can see exactly what they sent
81
        LOGGER.info("report-handler raw params from Knowlarity: {}", request.getParameterMap());
82
        try {
83
            LOGGER.info("first event call detail (mapped): {}", callDetail);
84
            recordingService.updateAgentRecording(callDetail);
85
        } catch (Exception e) {
86
            LOGGER.error("Error processing report-handler webhook. Raw params: {}", request.getParameterMap(), e);
87
        }
33581 ranu 88
        return responseSender.ok(true);
32917 amit.gupta 89
    }
33581 ranu 90
 
91
 
35624 ranu 92
    /**
93
     * Knowlarity Click2Call Webhook - Recording URL Update.
94
     *
95
     * This endpoint is called by Knowlarity after a call recording is available.
96
     * Knowlarity sends updated call detail (including the recording URL) as form-urlencoded POST,
97
     * mapped to {@link CallDetailModel}.
98
     *
99
     * The incoming third-party data from Knowlarity may not always match our expected model fields.
100
     * If Knowlarity changes their payload structure or sends unexpected/null values,
101
     * errors can occur during binding or in {@link RecordingService#updateAgentRecordingUrl}.
102
     *
103
     * URL: POST /click2call/report-handler/recording-url
104
     * Content-Type: application/x-www-form-urlencoded
105
     * Third-party: Knowlarity
106
     */
33590 ranu 107
    @RequestMapping(value = "/click2call/report-handler/recording-url", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
33591 ranu 108
    public ResponseEntity<?> click2callReportHandlerUpdateRecordingUrlPost(HttpServletRequest request, Model model, @ModelAttribute CallDetailModel callDetail) throws Exception {
35624 ranu 109
        // Log raw parameters from Knowlarity before processing, so we can see exactly what they sent
110
        LOGGER.info("recording-url raw params from Knowlarity: {}", request.getParameterMap());
111
        try {
112
            LOGGER.info("update call detail (mapped): {}", callDetail);
113
            recordingService.updateAgentRecordingUrl(callDetail);
114
        } catch (Exception e) {
115
            LOGGER.error("Error processing recording-url webhook. Raw params: {}", request.getParameterMap(), e);
116
        }
33581 ranu 117
        return responseSender.ok(true);
118
    }
33672 ranu 119
 
35624 ranu 120
    /**
121
     * Knowlarity Click2Call Webhook - Push Call Log.
122
     *
123
     * This endpoint is called by Knowlarity to push call log data in JSON format,
124
     * mapped to {@link PushCallLogModel}.
125
     *
126
     * The incoming third-party data from Knowlarity may not always match our expected model fields.
127
     * If Knowlarity changes their JSON payload structure or sends unexpected/null values,
128
     * errors can occur during deserialization or in {@link RecordingService#updateAgentCallLog}.
129
     *
130
     * URL: POST /click2call/push-call-log-handler
131
     * Content-Type: application/json
132
     * Third-party: Knowlarity
133
     */
34530 ranu 134
    @RequestMapping(value = "/click2call/push-call-log-handler", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
35624 ranu 135
    public ResponseEntity<?> click2callPushLogHandler(HttpServletRequest request, @RequestBody String rawBody) throws Exception {
136
        // Log raw JSON body from Knowlarity before processing, so we can see exactly what they sent
137
        LOGGER.info("push-call-log raw JSON from Knowlarity: {}", rawBody);
138
        try {
139
            ObjectMapper objectMapper = new ObjectMapper();
140
            PushCallLogModel pushCallLogModel = objectMapper.readValue(rawBody, PushCallLogModel.class);
141
            LOGGER.info("update call detail - push log (mapped): {}", pushCallLogModel);
142
            recordingService.updateAgentCallLog(pushCallLogModel);
143
        } catch (Exception e) {
144
            LOGGER.error("Error processing push-call-log webhook. Raw JSON: {}", rawBody, e);
145
        }
34530 ranu 146
        return responseSender.ok("true");
34481 ranu 147
    }
33672 ranu 148
 
34481 ranu 149
 
33672 ranu 150
    @Value("${razorpay.account.keySecret}")
151
    private String razorpaySecret;
152
    @Autowired
153
    private UpsellRazorpayPaymentStatusRepository upsellRazorpayPaymentStatusRepository;
154
 
33684 ranu 155
    @RequestMapping(value = "/upsellPayment/callback", method = RequestMethod.GET)
33715 ranu 156
    public ResponseEntity<?> handleCallback(HttpServletRequest request) {
33672 ranu 157
        try {
33688 ranu 158
            // Retrieve the Razorpay parameters from the query string
33684 ranu 159
            String paymentId = request.getParameter("razorpay_payment_id");
33688 ranu 160
            String razorpaySignature = request.getParameter("razorpay_signature");
33693 ranu 161
            String paymentLinkId = request.getParameter("razorpay_payment_link_id");
33715 ranu 162
            String paymentLinkStatus = request.getParameter("razorpay_payment_link_status");
163
            String paymentLinkReferenceId = request.getParameter("razorpay_payment_link_reference_id");
33693 ranu 164
 
33684 ranu 165
            String orderId = request.getParameter("orderId");
166
            String insuranceAmount = request.getParameter("insuranceAmount");
167
 
33688 ranu 168
            // Check for required parameters
169
            if (paymentId == null || razorpaySignature == null || orderId == null || insuranceAmount == null) {
33684 ranu 170
                return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Missing required parameters");
171
            }
172
 
33715 ranu 173
            JSONObject options = new JSONObject();
174
            options.put("payment_link_reference_id", paymentLinkReferenceId);
175
            options.put("razorpay_payment_id", paymentId);
176
            options.put("payment_link_status", paymentLinkStatus);
177
            options.put("payment_link_id", paymentLinkId);
178
            options.put("razorpay_signature", razorpaySignature);
33684 ranu 179
 
33715 ranu 180
            boolean status = Utils.verifyPaymentLink(options, razorpaySecret);
33693 ranu 181
 
33715 ranu 182
            LOGGER.info("status signature {}", status);
183
 
184
            if (!status) {
33672 ranu 185
                return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Invalid signature");
186
            }
33715 ranu 187
            FofoOrder fofoOrder = fofoOrderRepository.selectByOrderId(Integer.parseInt(orderId));
188
            Customer customer = customerRepository.selectById(fofoOrder.getCustomerId());
189
            // Handle the payment status (you may need to add more logic depending on the status)
190
            updatePaymentStatus(paymentId, paymentLinkReferenceId, "captured", orderId, insuranceAmount);
33672 ranu 191
 
33715 ranu 192
            // Construct the HTML response
193
            String htmlResponse = "<html>" +
194
                    "<head>" +
195
                    "<style>" +
196
                    "  .container { background-color: #f0f0f0; padding: 20px; text-align: center; border-radius: 8px;max-width:600px;width:auto;margin:10px auto; }" +
197
                    "  .success-icon { color: green; font-size:30px; margin-right: 10px;border-radius: 50%;border: 2px solid;padding: 1px 7px; }" +
198
                    "  .message { font-size: 18px; margin-top: 10px; }" +
199
                    "</style>" +
200
                    "</head>" +
201
                    "<body>" +
202
                    "  <div class='container'>" +
203
                    "    <span class='success-icon'>&#10003;</span>" +
204
                    "    <div class='message'>" +
205
                    "      Hi " + customer.getFirstName() + ",<br>" +
206
                    "      Your payment of " + insuranceAmount + " was successfully completed.<br>" +
207
                    "      Your payment ID is: " + paymentId + "." +
208
                    "    </div>" +
209
                    "  </div>" +
210
                    "</body>" +
211
                    "</html>";
33689 ranu 212
 
33715 ranu 213
            return ResponseEntity.ok().contentType(MediaType.TEXT_HTML).body(htmlResponse);
214
 
33672 ranu 215
        } catch (Exception e) {
216
            e.printStackTrace();
33715 ranu 217
 
33672 ranu 218
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error processing callback");
219
        }
220
    }
221
 
33684 ranu 222
 
33715 ranu 223
    private void updatePaymentStatus(String paymentId, String paymentLinkReferenceId, String status, String orderId, String amount) throws ProfitMandiBusinessException {
224
        int id = Integer.parseInt(paymentLinkReferenceId.replaceFirst("^0+(?!$)", ""));
225
        UpsellRazorpayPaymentStatus upsellRazorpayPaymentStatus = upsellRazorpayPaymentStatusRepository.selectById(id);
33672 ranu 226
        upsellRazorpayPaymentStatus.setPaymentId(paymentId);
33715 ranu 227
        upsellRazorpayPaymentStatus.setReferenceId(paymentLinkReferenceId);
33672 ranu 228
        upsellRazorpayPaymentStatus.setPaymentStatus(status);
33682 ranu 229
        upsellRazorpayPaymentStatus.setPayment(Float.parseFloat(amount));
33672 ranu 230
    }
32916 amit.gupta 231
}