Subversion Repositories SmartDukaan

Rev

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

Rev Author Line No. Line
25822 amit.gupta 1
package com.spice.profitmandi.service;
2
 
3
import com.google.gson.Gson;
30025 amit.gupta 4
import com.spice.profitmandi.common.enumuration.MessageType;
29198 manish 5
import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
37409 vikas 6
import com.spice.profitmandi.common.model.CustomRetailer;
29927 amit.gupta 7
import com.spice.profitmandi.common.model.ProfitMandiConstants;
25822 amit.gupta 8
import com.spice.profitmandi.common.model.SendNotificationModel;
29927 amit.gupta 9
import com.spice.profitmandi.dao.entity.auth.AuthUser;
32405 jai.hind 10
import com.spice.profitmandi.dao.entity.dtr.*;
36064 aman 11
import com.spice.profitmandi.dao.entity.fofo.Customer;
25822 amit.gupta 12
import com.spice.profitmandi.dao.entity.user.Device;
32405 jai.hind 13
import com.spice.profitmandi.dao.entity.whatsapp.WhatsappMessage;
25822 amit.gupta 14
import com.spice.profitmandi.dao.model.SimpleCampaign;
15
import com.spice.profitmandi.dao.model.SimpleCampaignParams;
16
import com.spice.profitmandi.dao.repository.catalog.DeviceRepository;
29927 amit.gupta 17
import com.spice.profitmandi.dao.repository.cs.CsService;
35207 amit 18
import com.spice.profitmandi.dao.repository.cs.PartnerRegionRepository;
32405 jai.hind 19
import com.spice.profitmandi.dao.repository.dtr.*;
36064 aman 20
import com.spice.profitmandi.dao.repository.fofo.CustomerRepository;
32405 jai.hind 21
import com.spice.profitmandi.dao.repository.whatsapp.WhatsappMessageRepository;
29198 manish 22
import com.spice.profitmandi.service.user.RetailerService;
37388 vikas 23
import com.spice.profitmandi.service.whatsapp.WhatsappFlow;
32405 jai.hind 24
import com.spice.profitmandi.service.whatsapp.WhatsappMessageService;
32854 amit.gupta 25
import com.spice.profitmandi.service.whatsapp.WhatsappMessageType;
37388 vikas 26
import com.spice.profitmandi.service.whatsapp.WhatsappNumbers;
37409 vikas 27
import com.spice.profitmandi.service.whatsapp.BotPenguinWhatsappService;
32405 jai.hind 28
import org.apache.logging.log4j.LogManager;
29
import org.apache.logging.log4j.Logger;
30
import org.springframework.beans.factory.annotation.Autowired;
34522 ranu 31
import org.springframework.beans.factory.annotation.Value;
32405 jai.hind 32
import org.springframework.stereotype.Component;
25822 amit.gupta 33
 
34545 vikas.jang 34
import java.nio.charset.StandardCharsets;
32508 amit.gupta 35
import java.time.LocalDate;
32405 jai.hind 36
import java.time.LocalDateTime;
37
import java.util.*;
38
import java.util.stream.Collectors;
39
 
25835 amit.gupta 40
@Component
25822 amit.gupta 41
public class NotificationServiceImpl implements NotificationService {
42
 
35236 amit 43
    private static final Logger LOGGER = LogManager.getLogger(NotificationServiceImpl.class);
37051 amit 44
 
45
    // Region id that represents "all partners". Schemes meant for everyone are tagged to this region;
46
    // partner_region is not populated for it, so it must be expanded to all partners here.
47
    private static final int ALL_PARTNERS_REGION = 5;
48
 
32253 amit.gupta 49
    @Autowired
50
    UserCampaignRepository userCampaignRepository;
51
    @Autowired
52
    UserRepository dtrUserRepository;
53
    @Autowired
54
    UserAccountRepository userAccountRepository;
55
    @Autowired
56
    NotificationCampaignRepository notificationCampaignRepository;
57
    @Autowired
58
    DeviceRepository deviceRepository;
35207 amit 59
 
32253 amit.gupta 60
    @Autowired
35207 amit 61
    PartnerRegionRepository partnerRegionRepository;
62
 
63
 
64
    @Autowired
32253 amit.gupta 65
    FofoStoreRepository fofoStoreRepository;
66
    @Autowired
67
    CsService csService;
68
    @Autowired
69
    RetailerService retailerService;
70
    @Autowired
36064 aman 71
    CustomerRepository customerRepository;
72
    @Autowired
32253 amit.gupta 73
    PushNotificationRepository pushNotificationRepository;
74
    @Autowired
75
    private Gson gson;
34522 ranu 76
    @Value("${prod}")
77
    private boolean isProd;
25822 amit.gupta 78
 
32405 jai.hind 79
    @Autowired
32417 amit.gupta 80
    private WhatsappMessageRepository whatsappMessageRepository;
32405 jai.hind 81
 
82
    @Autowired
83
    private WhatsappMessageService whatsappMessageService;
84
 
36962 vikas 85
    @Autowired
37409 vikas 86
    private BotPenguinWhatsappService botPenguin;
36962 vikas 87
 
32253 amit.gupta 88
    @Override
89
    public void sendNotification(SendNotificationModel sendNotificationModel) throws ProfitMandiBusinessException {
29927 amit.gupta 90
 
32253 amit.gupta 91
        SimpleCampaignParams scp = new SimpleCampaignParams();
92
        scp.setMessage(sendNotificationModel.getMessage());
93
        scp.setTitle(sendNotificationModel.getTitle());
94
        scp.setImageUrl(sendNotificationModel.getImageUrl());
95
        scp.setType(sendNotificationModel.getType());
96
        scp.setUrl(sendNotificationModel.getUrl());
97
        scp.setShowImage(sendNotificationModel.getShowImage());
98
        scp.setExpireTimestamp(sendNotificationModel.getExpiresat());
99
        SimpleCampaign sc = new SimpleCampaign(scp);
100
        sc.setSimpleCampaignParams(scp);
30025 amit.gupta 101
 
32253 amit.gupta 102
        NotificationCampaign nc = new NotificationCampaign();
103
        nc.setName(sendNotificationModel.getCampaignName());
104
        nc.setImplementationType("SimpleCampaign");
105
        nc.setImplementationParams(gson.toJson(scp));
106
        nc.setMessageType(sendNotificationModel.getMessageType());
107
        nc.setDocumentId(sendNotificationModel.getDocumentId());
108
        nc.setCreatedTimestamp(LocalDateTime.now());
109
        notificationCampaignRepository.persist(nc);
25822 amit.gupta 110
 
32253 amit.gupta 111
        Set<Integer> userIds = new HashSet<>();
112
        if (sendNotificationModel.getUserIds() != null && sendNotificationModel.getUserIds().size() > 0) {
113
            userIds.addAll(sendNotificationModel.getUserIds());
114
        }
29198 manish 115
 
32253 amit.gupta 116
        if (sendNotificationModel.getStateIds() != null && sendNotificationModel.getStateIds().size() > 0) {
33025 amit.gupta 117
            List<Integer> fofoIds = fofoStoreRepository.selectByWarehouseIds(sendNotificationModel.getStateIds()).stream()
118
                    .map(x -> x.getId()).collect(Collectors.toList());
34204 tejus.loha 119
            if (fofoIds.size() > 0) {
33025 amit.gupta 120
                userIds.addAll(userAccountRepository.selectUserIdsByRetailerIds(fofoIds));
121
            }
122
 
32253 amit.gupta 123
        }
35207 amit 124
        if(sendNotificationModel.getRegionIds() != null && sendNotificationModel.getRegionIds().size() > 0) {
37051 amit 125
            if (sendNotificationModel.getRegionIds().contains(ALL_PARTNERS_REGION)) {
126
                // "ALL partners" region: partner_region only holds a sentinel, so expand to every partner.
127
                userIds.addAll(fofoStoreRepository.selectAllDtrUserIds());
128
            } else {
129
                List<Integer> fofoIds = partnerRegionRepository.selectAllByRegionIds(sendNotificationModel.getRegionIds()).stream().map(x->x.getFofoId()).collect(Collectors.toList());
130
                if(fofoIds.size()>0) {
131
                    userIds.addAll(userAccountRepository.selectUserIdsByRetailerIds(fofoIds));
132
                }
35207 amit 133
            }
134
        }
29927 amit.gupta 135
 
34204 tejus.loha 136
        if (userIds.size() > 0) {
33025 amit.gupta 137
            for (Integer userId : userIds) {
138
                UserCampaign uc = new UserCampaign();
139
                uc.setCampaignId(nc.getId());
140
                uc.setUserId(userId);
141
                uc.setPushTimestamp(LocalDateTime.now());
142
                userCampaignRepository.persist(uc);
143
            }
144
            List<Device> devices = deviceRepository.selectByUserIdAndModifiedTimestamp(new ArrayList<>(userIds),
145
                    LocalDateTime.now().minusMonths(1), LocalDateTime.now());
146
            pushNotification(nc.getId(), devices);
147
        } else {
148
            LOGGER.info("Failed to send notification to any retailer with this model - {}", sendNotificationModel);
32253 amit.gupta 149
        }
25822 amit.gupta 150
 
32253 amit.gupta 151
    }
25822 amit.gupta 152
 
32253 amit.gupta 153
    @Override
154
    public void sendNotificationToAll(SendNotificationModel sendNotificationModel) throws ProfitMandiBusinessException {
155
        sendNotificationModel.setUserIds(fofoStoreRepository.selectAllDtrUserIds());
156
        Set<AuthUser> authUsers = new HashSet<>(
157
                csService.getAuthUserByCategoryId(ProfitMandiConstants.TICKET_CATEGORY_RBM));
158
        authUsers.addAll(csService.getAuthUserByCategoryId(ProfitMandiConstants.TICKET_CATEGORY_CATEGORY));
159
        authUsers.addAll(csService.getAuthUserByCategoryId(ProfitMandiConstants.TICKET_CATEGORY_SALES));
34903 ranu 160
        authUsers.addAll(csService.getAuthUserByCategoryId(ProfitMandiConstants.TICKET_CATEGORY_ABM));
32253 amit.gupta 161
        List<String> emailIds = authUsers.stream().map(x -> x.getEmailId()).collect(Collectors.toList());
162
        emailIds.add("devkinandan.lal@smartdukaan.com");
163
        List<User> systemUsers = dtrUserRepository.selectAllByEmailIds(emailIds);
32405 jai.hind 164
        sendNotificationModel.getUserIds()
165
                .addAll(systemUsers.stream().map(x -> x.getId()).collect(Collectors.toList()));
32253 amit.gupta 166
        this.sendNotification(sendNotificationModel);
167
    }
25822 amit.gupta 168
 
32253 amit.gupta 169
    @Override
34550 vikas.jang 170
    public void sendNotificationToSystemUsers(SendNotificationModel sendNotificationModel) throws ProfitMandiBusinessException {
171
        Set<AuthUser> authUsers = new HashSet<>(csService.getAuthUserByCategoryId(ProfitMandiConstants.TICKET_CATEGORY_RBM));
172
        authUsers.addAll(csService.getAuthUserByCategoryId(ProfitMandiConstants.TICKET_CATEGORY_CATEGORY));
173
        authUsers.addAll(csService.getAuthUserByCategoryId(ProfitMandiConstants.TICKET_CATEGORY_SALES));
34903 ranu 174
        authUsers.addAll(csService.getAuthUserByCategoryId(ProfitMandiConstants.TICKET_CATEGORY_ABM));
34550 vikas.jang 175
        List<String> emailIds = authUsers.stream().map(x -> x.getEmailId()).collect(Collectors.toList());
176
        emailIds.add("devkinandan.lal@smartdukaan.com");
177
        List<User> systemUsers = dtrUserRepository.selectAllByEmailIds(emailIds);
178
        sendNotificationModel.setUserIds(systemUsers.stream().map(x -> x.getId()).collect(Collectors.toList()));
179
        this.sendNotification(sendNotificationModel);
180
    }
181
 
182
    @Override
32405 jai.hind 183
    public void sendNotification(int fofoId, String campaignName, MessageType messageType, String title, String message)
184
            throws ProfitMandiBusinessException {
32253 amit.gupta 185
        SendNotificationModel sendNotificationModel = this.getDefaultNotificationModel();
186
        sendNotificationModel.setCampaignName(campaignName);
187
        sendNotificationModel.setMessageType(messageType);
188
        sendNotificationModel.setTitle(title);
189
        sendNotificationModel.setMessage(message);
190
        int userId = userAccountRepository.selectUserIdByRetailerId(fofoId);
191
        sendNotificationModel.setUserIds(Arrays.asList(userId));
192
        sendNotificationModel.setMessageType(MessageType.wallet);
193
        this.sendNotification(sendNotificationModel);
194
    }
25822 amit.gupta 195
 
32253 amit.gupta 196
    public SendNotificationModel getDefaultNotificationModel() {
197
        SendNotificationModel sendNotificationModel = new SendNotificationModel();
198
        sendNotificationModel.setType("url");
35840 vikas 199
        sendNotificationModel.setUrl("https://app.smartdukaan.com/pages/home/notifications");
32253 amit.gupta 200
        sendNotificationModel.setExpiresat(LocalDateTime.now().plusDays(1));
201
        sendNotificationModel.setMessageType(MessageType.notification);
202
        return sendNotificationModel;
203
    }
25822 amit.gupta 204
 
32253 amit.gupta 205
    public void pushNotification(int cid, List<Device> devices) {
29198 manish 206
 
32253 amit.gupta 207
        for (Device device : devices) {
208
            PushNotifications pn = new PushNotifications();
209
            pn.setNotificationCampaignid(cid);
210
            pn.setDeviceId(device.getId());
211
            pn.setUserId(device.getUser_id());
212
            pushNotificationRepository.persist(pn);
213
        }
29198 manish 214
 
32253 amit.gupta 215
    }
29198 manish 216
 
32253 amit.gupta 217
    @Override
34545 vikas.jang 218
    public void sendNotification(int fofoId, String campaignName, MessageType messageType, String title, String message, String url) throws ProfitMandiBusinessException {
32253 amit.gupta 219
        SendNotificationModel sendNotificationModel = this.getDefaultNotificationModel();
220
        sendNotificationModel.setCampaignName(campaignName);
221
        sendNotificationModel.setMessageType(messageType);
222
        sendNotificationModel.setTitle(title);
223
        sendNotificationModel.setMessage(message);
224
        int userId = userAccountRepository.selectUserIdByRetailerId(fofoId);
225
        sendNotificationModel.setUserIds(Arrays.asList(userId));
226
        sendNotificationModel.setMessageType(messageType);
227
        sendNotificationModel.setUrl(url);
228
        this.sendNotification(sendNotificationModel);
229
    }
29198 manish 230
 
37409 vikas 231
    /**
232
     * Invoice PDF, sent as the template's document header.
233
     *
234
     * <p>The upsell wording that used to be built here now lives in the approved template; only the
235
     * recipient's name and the PDF link cross the wire.</p>
236
     */
32253 amit.gupta 237
    @Override
37409 vikas 238
    public boolean sendWhatsappInvoice(int customerId, int fofoId, String invoiceNumber, String whatsAppNo) throws Exception {
239
        if (!shouldSendWhatsappMessage(whatsAppNo)) {
240
            return false;
32874 amit.gupta 241
        }
36064 aman 242
        Customer customer = customerRepository.selectById(customerId);
243
        String mobileNumber = (whatsAppNo != null && !whatsAppNo.isEmpty()) ? whatsAppNo : customer.getMobileNumber();
244
 
245
        String mediaUrl = "https://partners.smartdukaan.com/wa-invoice-send/"
246
                + Base64.getMimeEncoder().encodeToString(invoiceNumber.getBytes(StandardCharsets.UTF_8)) + ".pdf";
247
        String fileName = "INV-" + invoiceNumber.replace("/", "-") + ".pdf";
248
 
249
        LOGGER.info("sendWhatsappInvoice: mobile={} mediaUrl={}", mobileNumber, mediaUrl);
37409 vikas 250
        return botPenguin.send(WhatsappFlow.INVOICE, mobileNumber,
251
                Arrays.asList(customerName(customer), storeName(fofoId)), mediaUrl, fileName,
252
                WhatsappMessageType.DOCUMENT);
36064 aman 253
    }
254
 
255
    @Override
37409 vikas 256
    public boolean sendPaymentLink(String mobile, String paymentLink) throws Exception {
257
        return botPenguin.send(WhatsappFlow.PAYMENT_LINK, mobile,
258
                Collections.singletonList(paymentLink), null, null, null);
32253 amit.gupta 259
    }
25822 amit.gupta 260
 
32253 amit.gupta 261
    @Override
37409 vikas 262
    public boolean sendOfferAnnouncement(String mobile, String offerName, String schemeType, String startDate,
263
                                         String endDate, String imageUrl) throws Exception {
264
        return botPenguin.send(WhatsappFlow.OFFER, mobile,
265
                Arrays.asList(offerName, schemeType, startDate, endDate), imageUrl, null,
266
                WhatsappMessageType.IMAGE);
32253 amit.gupta 267
    }
29927 amit.gupta 268
 
37409 vikas 269
    @Override
270
    public boolean sendBiddingLive(String mobile, List<String> lots, String mediaUrl) throws Exception {
271
        int slots = ProfitMandiConstants.WHATSAPP_TEMPLATE.BIDDING_LIVE.getBodyParamCount();
272
        if (lots.size() > slots) {
273
            LOGGER.warn("sendBiddingLive: {} lots available but the template holds {}; dropping {}",
274
                    lots.size(), slots, lots.subList(slots, lots.size()));
275
        }
276
        List<String> params = new ArrayList<>(lots.subList(0, Math.min(lots.size(), slots)));
277
        // Meta rejects an empty parameter, so unused slots carry a dash rather than "".
278
        while (params.size() < slots) {
279
            params.add("-");
280
        }
281
        return botPenguin.send(WhatsappFlow.BIDDING_LIVE, mobile, params, mediaUrl, null,
282
                WhatsappMessageType.IMAGE);
32253 amit.gupta 283
    }
30025 amit.gupta 284
 
32405 jai.hind 285
    @Override
37409 vikas 286
    public boolean sendLoanDefaultAlert(String mobile, String name, String outstandingAmount) throws Exception {
287
        LOGGER.info("Is Prod - {}", isProd);
288
        if (!isProd) {
289
            return false;
290
        }
291
        return botPenguin.send(WhatsappFlow.LOAN_ALERT, mobile,
292
                Arrays.asList(name, outstandingAmount), null, null, null);
293
    }
294
 
295
    @Override
296
    public boolean sendOrderDelivered(String mobile, String airwayBillNumber) throws Exception {
297
        LOGGER.info("Is Prod - {}", isProd);
298
        if (!isProd) {
299
            return false;
300
        }
301
        return botPenguin.send(WhatsappFlow.ORDER_DELIVERED, mobile,
302
                Collections.singletonList(airwayBillNumber), null, null, null);
303
    }
304
 
305
    @Override
306
    public boolean sendADLDWhatsappMessage(String mobile, String invoiceNumber, String mediaUrl,
307
                                           String fileName) throws Exception {
308
        LOGGER.info("Is Prod - {}", isProd);
309
        if (!isProd) {
310
            return false;
311
        }
312
        return botPenguin.send(WhatsappFlow.ADLD, mobile, Collections.singletonList(invoiceNumber),
313
                mediaUrl, fileName, WhatsappMessageType.DOCUMENT);
314
    }
315
 
316
    @Override
33415 amit.gupta 317
    public boolean shouldSendWhatsappMessage(String mobile) {
37409 vikas 318
        // Normalised rather than concatenated: BotPenguin stores the normalised MSISDN, so for anything
319
        // that is not already a bare ten digits the old "91" + mobile key could never match a stored row
320
        // and the throttle quietly never fired. Identical result for clean input.
37388 vikas 321
        String destAddr = WhatsappNumbers.toMsisdn(mobile);
322
        if (destAddr == null) {
323
            return true;
324
        }
33415 amit.gupta 325
        boolean shouldSend = true;
32508 amit.gupta 326
        List<WhatsappMessage> whatsappMessages = whatsappMessageRepository.selectByDestAddr(destAddr, LocalDate.now());
32405 jai.hind 327
        if (!whatsappMessages.isEmpty()) {
32508 amit.gupta 328
            long failedCount = whatsappMessages.stream().filter(x -> x.getFailed() != null && x.getFailed().equals("FAILED")).collect(Collectors.counting());
32405 jai.hind 329
            if (failedCount >= 2) {
33415 amit.gupta 330
                shouldSend = false;
32405 jai.hind 331
            }
332
        }
33415 amit.gupta 333
        return shouldSend;
32405 jai.hind 334
    }
33715 ranu 335
 
37409 vikas 336
    /**
337
     * The store the purchase was made at, for the invoice template's second variable. Falls back to the
338
     * brand name: an unknown partner id must not stop an invoice going out.
339
     */
340
    private String storeName(int fofoId) {
341
        try {
342
            CustomRetailer retailer = retailerService.getFofoRetailer(fofoId);
343
            String businessName = retailer == null ? null : retailer.getBusinessName();
344
            if (businessName != null && !businessName.trim().isEmpty()) {
345
                return businessName.trim();
346
            }
347
        } catch (Exception e) {
348
            LOGGER.warn("storeName: could not resolve fofoId {}", fofoId, e);
349
        }
350
        return "SmartDukaan";
351
    }
33715 ranu 352
 
37409 vikas 353
    /** Meta greets by name, so an empty first name would render "Hello ,". */
354
    private static String customerName(Customer customer) {
355
        String firstName = customer == null ? null : customer.getFirstName();
356
        return (firstName == null || firstName.trim().isEmpty()) ? "Customer" : firstName.trim();
33715 ranu 357
    }
34545 vikas.jang 358
 
25822 amit.gupta 359
}