Subversion Repositories SmartDukaan

Rev

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

Rev Author Line No. Line
27391 tejbeer 1
package com.spice.profitmandi.web.controller;
2
 
35923 aman 3
import com.google.gson.Gson;
29943 amit.gupta 4
import com.jcraft.jsch.*;
29900 amit.gupta 5
import com.spice.profitmandi.common.enumuration.MessageType;
27391 tejbeer 6
import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
7
import com.spice.profitmandi.common.model.CustomRetailer;
27876 amit.gupta 8
import com.spice.profitmandi.common.model.ProfitMandiConstants;
29900 amit.gupta 9
import com.spice.profitmandi.common.model.SendNotificationModel;
29904 amit.gupta 10
import com.spice.profitmandi.common.util.FormattingUtils;
27876 amit.gupta 11
import com.spice.profitmandi.common.web.util.ResponseSender;
35501 ranu 12
import com.spice.profitmandi.dao.entity.catalog.BrandCatalog;
27391 tejbeer 13
import com.spice.profitmandi.dao.entity.catalog.Offer;
14
import com.spice.profitmandi.dao.entity.fofo.PartnerType;
15
import com.spice.profitmandi.dao.enumuration.catalog.ItemCriteriaType;
30651 amit.gupta 16
import com.spice.profitmandi.dao.enumuration.catalog.OfferSchemeType;
27391 tejbeer 17
import com.spice.profitmandi.dao.model.CreateOfferRequest;
34176 tejus.loha 18
import com.spice.profitmandi.dao.model.ItemCriteriaPayout;
35501 ranu 19
import com.spice.profitmandi.dao.model.TodayOfferModel;
35923 aman 20
import com.spice.profitmandi.dao.repository.catalog.CatalogRepository;
21
import com.spice.profitmandi.dao.repository.catalog.ItemRepository;
22
import com.spice.profitmandi.dao.repository.catalog.OfferMarginRepository;
23
import com.spice.profitmandi.dao.repository.catalog.OfferRepository;
27391 tejbeer 24
import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;
29926 amit.gupta 25
import com.spice.profitmandi.dao.repository.dtr.UserAccountRepository;
29900 amit.gupta 26
import com.spice.profitmandi.service.NotificationService;
29785 amit.gupta 27
import com.spice.profitmandi.service.authentication.RoleManager;
33043 amit.gupta 28
import com.spice.profitmandi.service.catalog.BrandsService;
34176 tejus.loha 29
import com.spice.profitmandi.service.offers.ItemCriteria;
27876 amit.gupta 30
import com.spice.profitmandi.service.offers.OfferService;
35923 aman 31
import com.spice.profitmandi.service.offers.PartnerCriteria;
35501 ranu 32
import com.spice.profitmandi.service.offers.TodayOfferService;
27391 tejbeer 33
import com.spice.profitmandi.service.user.RetailerService;
34
import com.spice.profitmandi.web.model.LoginDetails;
35
import com.spice.profitmandi.web.util.CookiesProcessor;
36
import com.spice.profitmandi.web.util.MVCResponseSender;
29943 amit.gupta 37
import org.apache.commons.io.FileUtils;
38
import org.apache.commons.io.output.ByteArrayOutputStream;
39
import org.apache.logging.log4j.LogManager;
40
import org.apache.logging.log4j.Logger;
41
import org.springframework.beans.factory.annotation.Autowired;
32868 amit.gupta 42
import org.springframework.beans.factory.annotation.Value;
29943 amit.gupta 43
import org.springframework.cache.CacheManager;
35923 aman 44
import org.springframework.cache.interceptor.SimpleKey;
29943 amit.gupta 45
import org.springframework.core.io.InputStreamResource;
46
import org.springframework.http.HttpHeaders;
47
import org.springframework.http.HttpStatus;
48
import org.springframework.http.ResponseEntity;
32204 amit.gupta 49
import org.springframework.mock.web.MockHttpServletRequest;
50
import org.springframework.mock.web.MockHttpServletResponse;
29943 amit.gupta 51
import org.springframework.stereotype.Controller;
35501 ranu 52
import org.springframework.transaction.annotation.Transactional;
29943 amit.gupta 53
import org.springframework.ui.Model;
54
import org.springframework.web.bind.annotation.*;
55
import org.springframework.web.multipart.MultipartFile;
32204 amit.gupta 56
import org.springframework.web.servlet.View;
57
import org.springframework.web.servlet.ViewResolver;
29943 amit.gupta 58
import org.xhtmlrenderer.swing.Java2DRenderer;
27391 tejbeer 59
 
29943 amit.gupta 60
import javax.imageio.ImageIO;
61
import javax.servlet.http.HttpServletRequest;
62
import java.awt.*;
63
import java.awt.image.BufferedImage;
64
import java.io.ByteArrayInputStream;
65
import java.io.File;
66
import java.io.FileNotFoundException;
67
import java.io.InputStream;
33713 tejus.loha 68
import java.time.Instant;
69
import java.time.LocalDate;
70
import java.time.LocalDateTime;
71
import java.time.YearMonth;
35923 aman 72
import java.util.*;
35501 ranu 73
import java.util.List;
29943 amit.gupta 74
import java.util.stream.Collectors;
75
 
27391 tejbeer 76
@Controller
35458 amit 77
@Transactional(rollbackFor = Throwable.class)
27391 tejbeer 78
public class OfferController {
32505 amit.gupta 79
    private static final Logger LOGGER = LogManager.getLogger(OfferController.class);
80
    private static final String IMAGE_REMOTE_DIR = "/var/www/dtrdashboard/uploads/campaigns/";
81
    private static final String IMAGE_STATIC_SERVER_URL = "https://images.smartdukaan.com/uploads/campaigns";
82
    @Autowired
83
    UserAccountRepository userAccountRepository;
84
    @Autowired
85
    RoleManager roleManager;
86
    @Autowired
87
    private OfferRepository offerRepository;
88
    @Autowired
89
    private OfferMarginRepository offerMarginRepository;
90
    @Autowired
91
    private FofoStoreRepository fofoStoreRepository;
92
    @Autowired
93
    private ResponseSender responseSender;
94
    @Autowired
95
    private ViewResolver viewResolver;
96
    @Autowired
97
    private ItemRepository itemRepository;
98
    @Autowired
99
    private MVCResponseSender mvcResponseSender;
100
    @Autowired
101
    private RetailerService retailerService;
102
    @Autowired
103
    private NotificationService notificationService;
104
    @Autowired
105
    private CookiesProcessor cookiesProcessor;
106
    @Autowired
107
    private OfferService offerService;
108
    @Autowired
109
    private CacheManager oneDayCacheManager;
27391 tejbeer 110
 
33043 amit.gupta 111
    @Autowired
35857 amit 112
    private CacheManager redisCacheManager;
113
 
114
    @Autowired
115
    private CacheManager redisShortCacheManager;
116
 
117
    @Autowired
35892 amit 118
    private CacheManager thirtyMinsTimeOutCacheManager;
119
 
120
    @Autowired
35893 amit 121
    private Gson gson;
122
 
123
    @Autowired
33043 amit.gupta 124
    BrandsService brandsService;
34553 amit.gupta 125
 
34552 amit.gupta 126
    @Autowired
127
    private CatalogRepository catalogRepository;
33043 amit.gupta 128
 
35501 ranu 129
    @Autowired
130
    TodayOfferService todayOfferService;
131
 
32505 amit.gupta 132
    @RequestMapping(value = "/getCreateOffer", method = RequestMethod.GET)
133
    public String getCreateOffer(HttpServletRequest request, Model model) throws ProfitMandiBusinessException {
134
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
135
        List<Integer> fofoIds = fofoStoreRepository.selectActiveStores().stream().map(x -> x.getId())
136
                .collect(Collectors.toList());
27391 tejbeer 137
 
33713 tejus.loha 138
        Set<String> brands = brandsService.getBrandsToDisplay(3).stream().map(x -> x.getName()).collect(Collectors.toSet());
32505 amit.gupta 139
        brands.addAll(itemRepository.selectAllBrands(ProfitMandiConstants.LED_CATEGORY_ID));
33615 amit.gupta 140
        brands.addAll(itemRepository.selectAllBrands(ProfitMandiConstants.SMART_WATCH_CATEGORY_ID));
32505 amit.gupta 141
        //Lets allow demo
142
        brands.add("Live Demo");
27391 tejbeer 143
 
32505 amit.gupta 144
        Map<Integer, CustomRetailer> customRetailerMap = retailerService.getAllFofoRetailers();
27876 amit.gupta 145
 
32505 amit.gupta 146
        Map<Integer, CustomRetailer> customRetailersMap = fofoIds.stream().map(x -> customRetailerMap.get(x))
147
                .filter(x -> x != null).collect(Collectors.toList()).stream()
148
                .collect(Collectors.toMap(x -> x.getPartnerId(), x -> x));
32204 amit.gupta 149
 
32505 amit.gupta 150
        model.addAttribute("customRetailersMap", customRetailersMap);
151
        model.addAttribute("itemCriteriaType", ItemCriteriaType.values());
152
        model.addAttribute("brands", brands);
153
        model.addAttribute("partnerCategories", PartnerType.values());
154
        model.addAttribute("warehouseRegion", ProfitMandiConstants.WAREHOUSE_MAP);
155
        return "scheme_offer";
27391 tejbeer 156
 
32505 amit.gupta 157
    }
29926 amit.gupta 158
 
32505 amit.gupta 159
    @RequestMapping(value = "/createOffer", method = RequestMethod.POST)
160
    public String createOffer(HttpServletRequest request, @RequestBody CreateOfferRequest createOfferRequest,
161
                              Model model) throws Exception {
162
        LOGGER.info("createOfferRequest [{}]", createOfferRequest);
163
        offerService.addOfferService(createOfferRequest);
32868 amit.gupta 164
        oneDayCacheManager.getCache("allOffers").evict(YearMonth.from(createOfferRequest.getStartDate()));
32505 amit.gupta 165
        model.addAttribute("response1", mvcResponseSender.createResponseString(true));
166
        return "response";
27391 tejbeer 167
 
32505 amit.gupta 168
    }
27391 tejbeer 169
 
32505 amit.gupta 170
    @RequestMapping(value = "/offers/published", method = RequestMethod.GET)
171
    public String getPublishedOffers(HttpServletRequest request, @RequestParam int fofoId, Model model)
172
            throws Exception {
173
        LOGGER.info("Published");
174
        offerService.getPublishedOffers(fofoId, YearMonth.from(LocalDateTime.now()));
175
        return "scheme_offer/published";
27391 tejbeer 176
 
32505 amit.gupta 177
    }
27391 tejbeer 178
 
32868 amit.gupta 179
    @Value("${prod}")
180
    private boolean isProd;
181
 
32505 amit.gupta 182
    @RequestMapping(value = "/offer/active/{offerId}", method = RequestMethod.GET)
183
    public String activateOffer(HttpServletRequest request, @PathVariable(name = "offerId") String offerIdsString,
184
                                Model model, @RequestParam(defaultValue = "true") boolean active)
185
            throws ProfitMandiBusinessException, Exception {
186
        List<Integer> offerIds = Arrays.stream(offerIdsString.split(",")).map(x -> Integer.parseInt(x))
187
                .collect(Collectors.toList());
188
        List<Offer> offers = offerRepository.selectAllByIds(offerIds);
32868 amit.gupta 189
 
190
        //Consider only offers that have opposite status
191
        offers = offers.stream().filter(x -> x.isActive() != active).collect(Collectors.toList());
192
 
193
        Set<YearMonth> yearMonthsToEvict = new HashSet<>();
32505 amit.gupta 194
        for (Offer offer : offers) {
32868 amit.gupta 195
            offer.setActive(active);
196
            yearMonthsToEvict.add(YearMonth.from(offer.getStartDate()));
32505 amit.gupta 197
        }
35894 amit 198
        // Evict partner-to-offer mapping (which partners see which offers)
32868 amit.gupta 199
        for (YearMonth ymToEvict : yearMonthsToEvict) {
35857 amit 200
            redisCacheManager.getCache("catalog.published_yearmonth").evict(ymToEvict);
32868 amit.gupta 201
            oneDayCacheManager.getCache("allOffers").evict(ymToEvict);
32505 amit.gupta 202
        }
35894 amit 203
        // Evict partner's published offer list with achievement data
35925 amit 204
        oneDayCacheManager.getCache("publishedOffersWithAchievement").clear();
205
        redisShortCacheManager.getCache("todayOffers").clear();
35894 amit 206
        // Evict offer detail (price circular) for each involved partner; key=(fofoId, offerId), 0=admin
35893 amit 207
        for (Offer offer : offers) {
208
            PartnerCriteria partnerCriteria = gson.fromJson(offer.getPartnerCriteria(), PartnerCriteria.class);
209
            if (partnerCriteria != null && partnerCriteria.getFofoIds() != null) {
210
                for (Integer fofoId : partnerCriteria.getFofoIds()) {
211
                    thirtyMinsTimeOutCacheManager.getCache("partnerOffers").evict(new SimpleKey(fofoId, offer.getId()));
212
                }
213
            }
214
            thirtyMinsTimeOutCacheManager.getCache("partnerOffers").evict(new SimpleKey(0, offer.getId()));
215
        }
32868 amit.gupta 216
        if (active) {
217
            for (Offer offer : offers) {
32505 amit.gupta 218
                this.sendNotification(offer);
219
            }
220
        }
32868 amit.gupta 221
 
222
 
32505 amit.gupta 223
        model.addAttribute("response1", mvcResponseSender.createResponseString(true));
224
        return "response";
225
    }
27391 tejbeer 226
 
35857 amit 227
    @RequestMapping(value = "/offers/publishAll", method = RequestMethod.POST)
228
    public ResponseEntity<?> publishAllUnpublished(@RequestParam YearMonth yearMonth)
229
            throws ProfitMandiBusinessException, Exception {
230
        List<Offer> published = offerService.publishAllUnpublished(yearMonth);
231
        if (!published.isEmpty()) {
35894 amit 232
            // Evict partner-to-offer mapping and offer listing
35857 amit 233
            redisCacheManager.getCache("catalog.published_yearmonth").evict(yearMonth);
234
            oneDayCacheManager.getCache("allOffers").evict(yearMonth);
35925 amit 235
            oneDayCacheManager.getCache("publishedOffersWithAchievement").clear();
236
        redisShortCacheManager.getCache("todayOffers").clear();
35894 amit 237
            // Evict offer detail (price circular) for each involved partner; key=(fofoId, offerId), 0=admin
35857 amit 238
            for (Offer offer : published) {
35893 amit 239
                PartnerCriteria pc = gson.fromJson(offer.getPartnerCriteria(), PartnerCriteria.class);
240
                if (pc != null && pc.getFofoIds() != null) {
241
                    for (Integer fofoId : pc.getFofoIds()) {
242
                        thirtyMinsTimeOutCacheManager.getCache("partnerOffers").evict(new SimpleKey(fofoId, offer.getId()));
243
                    }
244
                }
245
                thirtyMinsTimeOutCacheManager.getCache("partnerOffers").evict(new SimpleKey(0, offer.getId()));
246
            }
247
            for (Offer offer : published) {
35857 amit 248
                this.sendNotification(offer);
249
            }
250
        }
251
        return responseSender.ok(published.size() + " offers published");
252
    }
253
 
254
    @RequestMapping(value = "/offer/delete/{offerId}", method = RequestMethod.DELETE)
255
    public ResponseEntity<?> deleteOffer(@PathVariable int offerId) throws ProfitMandiBusinessException {
256
        offerService.deleteOffer(offerId);
257
        return responseSender.ok(true);
258
    }
259
 
32505 amit.gupta 260
    @RequestMapping(value = "/offer/testimage/{offerId}", method = RequestMethod.GET)
261
    public String testOffer(HttpServletRequest request, @PathVariable int offerId, Model model,
262
                            @RequestParam(defaultValue = "true") boolean active) throws ProfitMandiBusinessException, Exception {
263
        Offer offer = offerRepository.selectById(offerId);
264
        // model.addAttribute("response1", mvcResponseSender.createResponseString(true));
265
        // return "response";
266
        CreateOfferRequest createOfferRequest = offerService.getCreateOfferRequest(offer);
267
        Map<String, Object> model1 = new HashMap<>();
268
        model1.put("offer", createOfferRequest);
269
        model1.put("lessThan", "<");
270
        String htmlContent = this.getContentFromTemplate("offer_margin_detail_notify", model1);
271
        model.addAttribute("response1", htmlContent);
272
        return "response";
273
    }
29900 amit.gupta 274
 
32505 amit.gupta 275
    private void sendNotification(Offer offer) throws Exception {
276
        if (!YearMonth.from(offer.getStartDate()).equals(YearMonth.now())) {
277
            return;
278
        }
279
        String fileName = "offer-" + offer.getId() + ".png";
32868 amit.gupta 280
        //String htmlFileName = fileName.replace("png", "html");
32505 amit.gupta 281
        CreateOfferRequest createOfferRequest = offerService.getCreateOfferRequest(offer);
34620 amit.gupta 282
        boolean isLiveDemo = createOfferRequest.getTargetSlabs().stream()
283
                .map(x -> x.getItemCriteriaPayouts())
284
                .flatMap(List::stream)
285
                .map(ItemCriteriaPayout::getItemCriteria)
286
                .map(ItemCriteria::getCatalogIds)
287
                .flatMap(List::stream)
288
                .anyMatch(catalogId -> catalogRepository.selectCatalogById(catalogId).getBrand().equals("Live Demo"));
289
        if (!isLiveDemo) {
290
            SendNotificationModel sendNotificationModel = new SendNotificationModel();
291
            sendNotificationModel.setCampaignName("SchemeOffer");
292
            sendNotificationModel.setTitle(offer.getName());
293
            sendNotificationModel.setMessage(createOfferRequest.getSchemeType().name() + " of select models, "
294
                    + FormattingUtils.formatDateMonth(offer.getStartDate()) + " to "
295
                    + FormattingUtils.formatDateMonth(offer.getEndDate()));
296
            sendNotificationModel.setType("url");
297
            String imageUrl = IMAGE_STATIC_SERVER_URL + "/" + "image" + LocalDate.now() + "/" + fileName;
298
            sendNotificationModel.setImageUrl(imageUrl);
299
            sendNotificationModel.setUrl("https://app.smartdukaan.com/pages/home/notifications");
300
            sendNotificationModel.setExpiresat(LocalDateTime.now().plusDays(1));
301
            sendNotificationModel.setMessageType(MessageType.scheme);
302
            //Map<Integer, List<Offer>> offersMap = offerRepository.selectAllPublishedMapByPartner(YearMonth.now());
29900 amit.gupta 303
 
34620 amit.gupta 304
            Map<String, InputStream> fileStreamsMap = new HashMap<>();
305
            Map<String, Object> model = new HashMap<>();
306
            model.put("offer", createOfferRequest);
307
            String htmlContent = this.getContentFromTemplate("offer_margin_detail_notify", model);
308
            LOGGER.info("this.getContentFromTemplate {}", htmlContent);
309
            fileStreamsMap.put(fileName, this.getImageBuffer(htmlContent));
310
            // fileStreamsMap.put(htmlFileName, new
311
            // ByteArrayInputStream(htmlContent.getBytes()));
312
            List<Integer> fofoIds = null;
313
            if (isProd) {
314
                this.uploadFile(fileStreamsMap);
315
            }
316
 
317
            List<Integer> fofoIdSet = new ArrayList<>(offerRepository.getEligibleFofoIds(offer));
318
            //LOGGER.info(fofoIdSet);
319
            List<Integer> userIds = userAccountRepository.selectUserIdsByRetailerIds(new ArrayList<>(fofoIdSet));
320
            sendNotificationModel.setUserIds(userIds);
321
            notificationService.sendNotification(sendNotificationModel);
322
            sendWhatsapp(offer, fofoIds, imageUrl);
32868 amit.gupta 323
        }
32505 amit.gupta 324
    }
27876 amit.gupta 325
 
32505 amit.gupta 326
    private void sendWhatsapp(Offer offer, List<Integer> fofoIds, String imageUrl) throws Exception {
35205 amit 327
        offerService.sendWhatsapp(offer, fofoIds, imageUrl);
32505 amit.gupta 328
    }
27391 tejbeer 329
 
32505 amit.gupta 330
    private InputStream asInputStream(BufferedImage bi) throws Exception {
331
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
332
        ImageIO.write(bi, "png", baos);
333
        return new ByteArrayInputStream(baos.toByteArray());
27391 tejbeer 334
 
32505 amit.gupta 335
    }
27391 tejbeer 336
 
32505 amit.gupta 337
    private ChannelSftp setupJsch() throws JSchException {
338
        JSch jsch = new JSch();
33471 amit.gupta 339
        Session jschSession = jsch.getSession("root", "172.105.58.16");
32505 amit.gupta 340
        // Session jschSession = jsch.getSession("root", "173.255.254.24");
341
        LOGGER.info("getClass().getResource(\"id_rsa\") {}",
342
                getClass().getClassLoader().getResource("id_rsa").getPath());
343
        jsch.addIdentity(getClass().getClassLoader().getResource("id_rsa").getPath());
344
        // jschSession.setPassword("spic@2015static0");
345
        jschSession.setConfig("StrictHostKeyChecking", "no");
346
        jschSession.connect();
347
        return (ChannelSftp) jschSession.openChannel("sftp");
348
    }
30426 tejbeer 349
 
32505 amit.gupta 350
    private void fileUpload(ChannelSftp channelSftp, Map<String, InputStream> streamsFileMap, String destinationPath)
351
            throws SftpException, FileNotFoundException {
27391 tejbeer 352
 
32505 amit.gupta 353
        channelSftp.cd(destinationPath);
354
        String folderName = "image" + LocalDate.now();
27391 tejbeer 355
 
32505 amit.gupta 356
        channelSftp.cd(destinationPath);
357
        SftpATTRS attrs = null;
27391 tejbeer 358
 
32505 amit.gupta 359
        // check if the directory is already existing
360
        try {
361
            attrs = channelSftp.stat(folderName);
362
        } catch (Exception e) {
363
            System.out.println(destinationPath + "/" + folderName + " not found");
364
        }
27391 tejbeer 365
 
32505 amit.gupta 366
        // else create a directory
367
        if (attrs == null) {
368
            channelSftp.mkdir(folderName);
369
            channelSftp.chmod(0755, ".");
370
        }
371
        channelSftp.cd(folderName);
27391 tejbeer 372
 
32505 amit.gupta 373
        for (Map.Entry<String, InputStream> streamsFileEntry : streamsFileMap.entrySet()) {
374
            channelSftp.put(streamsFileEntry.getValue(), streamsFileEntry.getKey(), ChannelSftp.OVERWRITE);
375
        }
27391 tejbeer 376
 
32505 amit.gupta 377
    }
29926 amit.gupta 378
 
32505 amit.gupta 379
    private void uploadFile(Map<String, InputStream> fileStreamsMap) throws Exception {
380
        ChannelSftp channelSftp = setupJsch();
381
        channelSftp.connect();
382
        this.fileUpload(channelSftp, fileStreamsMap, IMAGE_REMOTE_DIR + "");
383
        channelSftp.exit();
384
    }
27391 tejbeer 385
 
32505 amit.gupta 386
    private InputStream getImageBuffer(String html) throws Exception {
35923 aman 387
        // Sanitize HTML to valid XHTML for Flying Saucer (Java2DRenderer requires well-formed XML)
388
        org.jsoup.nodes.Document doc = org.jsoup.Jsoup.parse(html);
389
        doc.outputSettings().syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml);
390
        doc.outputSettings().escapeMode(org.jsoup.nodes.Entities.EscapeMode.xhtml);
391
        doc.outputSettings().charset("UTF-8");
392
        html = doc.html();
29900 amit.gupta 393
 
32505 amit.gupta 394
        String fileName = "/tmp/" + Instant.now().toEpochMilli();
395
        FileUtils.writeStringToFile(new File(fileName), html, "UTF-8");
396
        String address = "file:" + fileName;
397
        Java2DRenderer renderer = new Java2DRenderer(address, 400);
398
        RenderingHints hints = new RenderingHints(RenderingHints.KEY_COLOR_RENDERING,
399
                RenderingHints.VALUE_COLOR_RENDER_QUALITY);
400
        hints.add(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
401
        hints.add(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
402
        hints.add(new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC));
403
        renderer.setRenderingHints(hints);
404
        BufferedImage img = renderer.getImage();
405
        ByteArrayOutputStream os = new ByteArrayOutputStream();
406
        ImageIO.write(img, "png", os);
407
        return new ByteArrayInputStream(os.toByteArray());
408
    }
29926 amit.gupta 409
 
32505 amit.gupta 410
    private String getContentFromTemplate(String template, Map<String, Object> model) throws Exception {
411
        View resolvedView = viewResolver.resolveViewName(template, Locale.US);
412
        MockHttpServletResponse mockResp = new MockHttpServletResponse();
413
        MockHttpServletRequest req = new MockHttpServletRequest();
414
        LOGGER.info("Resolved view ->  {}, {}, {}, {}", resolvedView, model, req, mockResp);
415
        resolvedView.render(model, req, mockResp);
416
        return mockResp.getContentAsString();
417
    }
29926 amit.gupta 418
 
32505 amit.gupta 419
    @RequestMapping(value = "/offerHistory", method = RequestMethod.GET)
420
    public String getPaginatedOffers(HttpServletRequest request, @RequestParam YearMonth yearMonth, Model model)
421
            throws ProfitMandiBusinessException {
30017 amit.gupta 422
 
32505 amit.gupta 423
        List<CreateOfferRequest> publishedOffers = offerService.getAllOffers(yearMonth).values().stream()
424
                .sorted(Comparator.comparing(CreateOfferRequest::getId).reversed()).collect(Collectors.toList());
425
        model.addAttribute("offers", publishedOffers);
426
        model.addAttribute("yearMonth", yearMonth);
427
        model.addAttribute("currentMonth", yearMonth.equals(YearMonth.now()));
29926 amit.gupta 428
 
32505 amit.gupta 429
        return "offer_history";
430
    }
30723 amit.gupta 431
 
32505 amit.gupta 432
    @RequestMapping(value = "/offer-details", method = RequestMethod.GET)
433
    public String schemeDetails(HttpServletRequest request, @RequestParam int offerId, Model model)
434
            throws ProfitMandiBusinessException {
435
        CreateOfferRequest createOfferRequest = offerService.getOffer(0, offerId);
29900 amit.gupta 436
 
32505 amit.gupta 437
        model.addAttribute("offer", createOfferRequest);
438
        return "offer-details";
439
    }
29926 amit.gupta 440
 
32505 amit.gupta 441
    @RequestMapping(value = "/offer/process/{offerId}", method = RequestMethod.GET)
442
    public ResponseEntity<?> processOfferRequest(HttpServletRequest request, @PathVariable int offerId, Model model)
443
            throws Exception {
444
        CreateOfferRequest createOfferRequest = offerService.getOffer(0, offerId);
445
        if (!createOfferRequest.isActive()) {
446
            throw new ProfitMandiBusinessException("Offer not active", "Offer not active", "Offer not active");
447
        }
448
        if (createOfferRequest.getSchemeType().equals(OfferSchemeType.SELLIN)) {
449
            offerService.processSellin(createOfferRequest);
450
        } else if (createOfferRequest.getSchemeType().equals(OfferSchemeType.ACTIVATION)) {
451
            offerService.processActivationtOffer(createOfferRequest);
452
        }
453
        return responseSender.ok(true);
454
    }
29926 amit.gupta 455
 
32505 amit.gupta 456
    @RequestMapping(value = "/offerDownload", method = RequestMethod.GET)
457
    public ResponseEntity<?> dowloadOfferSummary(HttpServletRequest request, @RequestParam int offerId, Model model)
458
            throws Exception {
459
        final HttpHeaders headers = new HttpHeaders();
460
        headers.set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
461
        headers.set("Content-disposition", "inline; filename=offer-" + offerId + ".csv");
462
        CreateOfferRequest createOfferRequest = offerService.getOffer(0, offerId);
33999 tejus.loha 463
        ByteArrayOutputStream baos = offerService.createCSVOfferReport(createOfferRequest);
32505 amit.gupta 464
        final InputStream inputStream = new ByteArrayInputStream(baos.toByteArray());
465
        final InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
466
        return new ResponseEntity<>(inputStreamResource, headers, HttpStatus.OK);
467
    }
29900 amit.gupta 468
 
32505 amit.gupta 469
    @RequestMapping(value = "/offerById", method = RequestMethod.GET)
470
    public String offerById(HttpServletRequest request, int offerId, Model model) throws ProfitMandiBusinessException {
471
        Offer offer = offerRepository.selectById(offerId);
472
        model.addAttribute("offer", offer);
473
        return "offer-edit";
29900 amit.gupta 474
 
32505 amit.gupta 475
    }
29900 amit.gupta 476
 
34176 tejus.loha 477
    @RequestMapping(value = "/published-offers", method = RequestMethod.GET)
478
    public String publishedOffersOnMonthBefore(HttpServletRequest request, @RequestParam int yearMonth, @RequestParam(required = false, defaultValue = "") String brandFilter, Model model)
32505 amit.gupta 479
            throws ProfitMandiBusinessException {
34176 tejus.loha 480
        LOGGER.info("publishedOffersCalled");
32505 amit.gupta 481
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
482
        int fofoId = loginDetails.getFofoId();
483
        List<CreateOfferRequest> createOffers = offerService.getPublishedOffers(fofoId,
484
                YearMonth.from(LocalDate.now()).minusMonths(yearMonth));
29900 amit.gupta 485
 
34617 amit.gupta 486
        List<CreateOfferRequest> publishedOffers = null;
487
        if (!brandFilter.isEmpty()) {
488
            publishedOffers = createOffers.stream()
34176 tejus.loha 489
                    .filter(createOffer -> createOffer.getTargetSlabs().stream()
490
                            .map(x -> x.getItemCriteriaPayouts())
491
                            .flatMap(List::stream)
492
                            .map(ItemCriteriaPayout::getItemCriteria)
493
                            .map(ItemCriteria::getBrands)
494
                            .flatMap(List::stream)
495
                            .anyMatch(brand -> brand.equals(brandFilter)))
496
                    .collect(Collectors.toList());
34617 amit.gupta 497
        } else {
498
            publishedOffers = createOffers.stream().filter(createOffer -> createOffer.getTargetSlabs().stream()
34557 amit.gupta 499
                    .map(x -> x.getItemCriteriaPayouts())
500
                    .flatMap(List::stream)
501
                    .map(ItemCriteriaPayout::getItemCriteria)
34559 amit.gupta 502
                    .map(ItemCriteria::getCatalogIds)
34557 amit.gupta 503
                    .flatMap(List::stream)
34559 amit.gupta 504
                    .noneMatch(catalogId -> catalogRepository.selectCatalogById(catalogId).getBrand().equals("Live Demo"))).collect(Collectors.toList());
34176 tejus.loha 505
        }
29926 amit.gupta 506
 
34176 tejus.loha 507
        model.addAttribute("publishedOffers", publishedOffers);
508
 
32505 amit.gupta 509
        return "published-offers";
510
    }
29926 amit.gupta 511
 
32505 amit.gupta 512
    @PostMapping(value = "/offers/upload")
513
    public String uploadOffers(HttpServletRequest request, @RequestPart("file") MultipartFile targetFile, Model model)
514
            throws Exception {
515
        offerService.createOffers(targetFile.getInputStream());
516
        model.addAttribute("response1", true);
517
        return "response";
518
    }
29926 amit.gupta 519
 
32505 amit.gupta 520
    @RequestMapping(value = "/getOfferMargins", method = RequestMethod.GET)
521
    public String getOfferMargins(HttpServletRequest request,
522
                                  @RequestParam(name = "offerId", defaultValue = "0") int offerId, Model model) throws Exception {
523
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
524
        boolean isAdmin = roleManager.isAdmin(loginDetails.getRoleIds());
525
        CreateOfferRequest createOfferRequest = offerService.getOffer(isAdmin ? 0 : loginDetails.getFofoId(), offerId);
29900 amit.gupta 526
 
32505 amit.gupta 527
        model.addAttribute("offer", createOfferRequest);
35415 amit 528
        model.addAttribute("isAdmin", isAdmin);
29900 amit.gupta 529
 
32505 amit.gupta 530
        return "offer_margin_detail_partner";
30470 amit.gupta 531
 
32505 amit.gupta 532
    }
29900 amit.gupta 533
 
35501 ranu 534
    @RequestMapping(value = "/todayOffer")
535
    public String todayOffer(HttpServletRequest request, Model model, @RequestParam(name = "fofoId", defaultValue = "0") int fofoId) throws ProfitMandiBusinessException {
536
 
537
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
538
        if (fofoId == 0) {
539
            fofoId = loginDetails.getFofoId();
540
        }
541
        List<BrandCatalog> allBrands = brandsService.getBrandsToDisplay(3);
542
 
543
        // 1. IDs to exclude entirely
544
        List<Integer> excludedIds = Arrays.asList(132, 133, 28, 17, 125);
545
 
546
        // 2. Brands that must come first (in this specific order)
547
        List<String> priorityOrder = Arrays.asList("Samsung", "Oppo", "Vivo", "Xiaomi", "Realme");
548
 
549
        List<BrandCatalog> sortedBrands = allBrands.stream()
550
                .filter(brand -> !excludedIds.contains(brand.getId())) // Remove excluded
551
                .sorted((b1, b2) -> {
552
                    // Get the index of the brand name in our priority list
553
                    int index1 = priorityOrder.indexOf(b1.getName());
554
                    int index2 = priorityOrder.indexOf(b2.getName());
555
 
556
                    // If brand is NOT in priority list, give it a high index (move to bottom)
557
                    int p1 = (index1 != -1) ? index1 : Integer.MAX_VALUE;
558
                    int p2 = (index2 != -1) ? index2 : Integer.MAX_VALUE;
559
 
560
                    if (p1 != p2) {
561
                        return Integer.compare(p1, p2); // Sort by priority first
562
                    }
563
 
564
                    // If both are "Others", sort them alphabetically
565
                    return b1.getName().compareToIgnoreCase(b2.getName());
566
                })
567
                .collect(Collectors.toList());
568
 
569
        model.addAttribute("brands", sortedBrands);
570
        model.addAttribute("fofoId", fofoId);
571
        model.addAttribute("date", FormattingUtils.format(LocalDateTime.now()));
572
 
573
        return "today-offer";
574
    }
575
 
576
    @RequestMapping(value = "/todayOfferList")
577
    public String todayOfferList(HttpServletRequest request, Model model, @RequestParam String brand, @RequestParam(defaultValue = "0", required = false) int fofoId) throws ProfitMandiBusinessException {
578
 
579
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
580
        if (fofoId == 0) {
581
            fofoId = loginDetails.getFofoId();
582
        }
583
 
584
        List<String> brands = brandsService.getBrandsToDisplay(3).stream().map(x -> x.getName()).collect(Collectors.toList());
585
 
586
        List<TodayOfferModel> todayOfferModels = todayOfferService.findAllTodayOffer(brand, fofoId);
587
 
588
        List<TodayOfferModel> groupedOffers = todayOfferService.groupSameOffers(todayOfferModels);
589
        model.addAttribute("brands", brands);
35505 ranu 590
        model.addAttribute("fofoId", fofoId);
35501 ranu 591
        model.addAttribute("todayOfferModels", todayOfferModels);
592
        model.addAttribute("groupedOffers", groupedOffers);
593
 
594
 
595
        return "today-offer-list";
596
    }
597
 
598
    @RequestMapping(value = "/todayFofoOffer")
599
    public String todayFofoOffer(HttpServletRequest request, Model model, @RequestParam(name = "fofoId", defaultValue = "0") int fofoId) throws ProfitMandiBusinessException {
600
 
601
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
602
        if (fofoId == 0) {
603
            fofoId = loginDetails.getFofoId();
604
        }
605
        List<BrandCatalog> allBrands = brandsService.getBrandsToDisplay(3);
606
 
607
        // 1. IDs to exclude entirely
608
        List<Integer> excludedIds = Arrays.asList(132, 133, 28, 17, 125);
609
 
610
        // 2. Brands that must come first (in this specific order)
611
        List<String> priorityOrder = Arrays.asList("Samsung", "Oppo", "Vivo", "Xiaomi", "Realme");
612
 
613
        List<BrandCatalog> sortedBrands = allBrands.stream()
614
                .filter(brand -> !excludedIds.contains(brand.getId())) // Remove excluded
615
                .sorted((b1, b2) -> {
616
                    // Get the index of the brand name in our priority list
617
                    int index1 = priorityOrder.indexOf(b1.getName());
618
                    int index2 = priorityOrder.indexOf(b2.getName());
619
 
620
                    // If brand is NOT in priority list, give it a high index (move to bottom)
621
                    int p1 = (index1 != -1) ? index1 : Integer.MAX_VALUE;
622
                    int p2 = (index2 != -1) ? index2 : Integer.MAX_VALUE;
623
 
624
                    if (p1 != p2) {
625
                        return Integer.compare(p1, p2); // Sort by priority first
626
                    }
627
 
628
                    // If both are "Others", sort them alphabetically
629
                    return b1.getName().compareToIgnoreCase(b2.getName());
630
                })
631
                .collect(Collectors.toList());
632
 
633
        model.addAttribute("brands", sortedBrands);
634
        model.addAttribute("fofoId", fofoId);
635
        model.addAttribute("date", FormattingUtils.format(LocalDateTime.now()));
636
 
637
        return "today-fofo-offer";
638
    }
639
 
35886 amit 640
    // ===== Offer Partner & Target Management (Admin Only) =====
641
 
642
    @RequestMapping(value = "/offer/partners", method = RequestMethod.GET)
643
    public String getOfferPartners(HttpServletRequest request, @RequestParam int offerId, Model model) throws Exception {
644
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
645
        if (!roleManager.isAdmin(loginDetails.getRoleIds())) {
646
            throw new ProfitMandiBusinessException("Unauthorized", "Unauthorized", "");
647
        }
648
        CreateOfferRequest offer = offerService.getOffer(0, offerId);
649
        Map<Integer, CustomRetailer> customRetailerMap = retailerService.getAllFofoRetailers();
650
 
35888 amit 651
        // Partners are stored in partner_criteria JSON, not in offer_partners table
652
        List<Integer> partnerFofoIds = offer.getPartnerCriteria() != null
653
                ? offer.getPartnerCriteria().getFofoIds() : new ArrayList<>();
654
        if (partnerFofoIds == null) partnerFofoIds = new ArrayList<>();
655
 
35886 amit 656
        List<Integer> allFofoIds = fofoStoreRepository.selectActiveStores().stream()
657
                .map(x -> x.getId()).collect(Collectors.toList());
658
        Map<Integer, CustomRetailer> allRetailersMap = allFofoIds.stream()
659
                .map(id -> customRetailerMap.get(id))
660
                .filter(x -> x != null)
661
                .collect(Collectors.toMap(CustomRetailer::getPartnerId, x -> x));
662
 
663
        model.addAttribute("offer", offer);
664
        model.addAttribute("offerId", offerId);
35888 amit 665
        model.addAttribute("partnerFofoIds", partnerFofoIds);
35886 amit 666
        model.addAttribute("customRetailerMap", customRetailerMap);
667
        model.addAttribute("allRetailersMap", allRetailersMap);
668
        return "offer_partners";
669
    }
670
 
671
    @RequestMapping(value = "/offer/removePartners", method = RequestMethod.POST)
672
    public ResponseEntity<?> removePartnersFromOffer(HttpServletRequest request,
673
            @RequestParam int offerId, @RequestParam List<Integer> fofoIds,
674
            @RequestParam(required = false, defaultValue = "false") boolean createNewOffer,
675
            @RequestParam(required = false) List<Integer> targets) throws Exception {
676
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
677
        if (!roleManager.isAdmin(loginDetails.getRoleIds())) {
678
            throw new ProfitMandiBusinessException("Unauthorized", "Unauthorized", "");
679
        }
680
        Offer offer = offerRepository.selectById(offerId);
681
        YearMonth ym = YearMonth.from(offer.getStartDate());
682
 
683
        offerService.removePartnersFromOffer(offerId, fofoIds);
684
 
685
        Integer newOfferId = null;
686
        String message;
687
        if (createNewOffer && targets != null && !targets.isEmpty()) {
688
            newOfferId = offerService.cloneOfferForPartners(offerId, fofoIds, targets);
689
            message = "Partner(s) removed from Offer #" + offerId + ". New Offer #" + newOfferId + " created (Unpublished).";
690
        } else {
691
            message = "Partner(s) removed from Offer #" + offerId + ".";
692
        }
693
 
35894 amit 694
        // Evict partner-to-offer mapping (removed partners no longer see this offer)
35892 amit 695
        oneDayCacheManager.getCache("allOffers").evict(ym);
696
        redisCacheManager.getCache("catalog.published_yearmonth").evict(ym);
35925 amit 697
        oneDayCacheManager.getCache("publishedOffersWithAchievement").clear();
698
        redisShortCacheManager.getCache("todayOffers").clear();
35894 amit 699
        // Evict offer detail (price circular) for removed partners; key=(fofoId, offerId), 0=admin
35892 amit 700
        for (Integer fofoId : fofoIds) {
701
            thirtyMinsTimeOutCacheManager.getCache("partnerOffers").evict(new SimpleKey(fofoId, offerId));
702
        }
703
        thirtyMinsTimeOutCacheManager.getCache("partnerOffers").evict(new SimpleKey(0, offerId));
704
 
35886 amit 705
        Map<String, Object> response = new HashMap<>();
706
        response.put("message", message);
707
        response.put("newOfferId", newOfferId);
708
        response.put("yearMonth", ym.toString());
709
        return responseSender.ok(response);
710
    }
711
 
712
    @RequestMapping(value = "/offer/addPartners", method = RequestMethod.POST)
713
    public ResponseEntity<?> addPartnersToOffer(HttpServletRequest request,
714
            @RequestParam int offerId, @RequestParam List<Integer> fofoIds) throws Exception {
715
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
716
        if (!roleManager.isAdmin(loginDetails.getRoleIds())) {
717
            throw new ProfitMandiBusinessException("Unauthorized", "Unauthorized", "");
718
        }
719
        offerService.addPartnersToOffer(offerId, fofoIds);
720
 
721
        Offer offer = offerRepository.selectById(offerId);
722
        YearMonth ym = YearMonth.from(offer.getStartDate());
35894 amit 723
        // Evict partner-to-offer mapping (added partners now see this offer)
35892 amit 724
        oneDayCacheManager.getCache("allOffers").evict(ym);
725
        redisCacheManager.getCache("catalog.published_yearmonth").evict(ym);
35925 amit 726
        oneDayCacheManager.getCache("publishedOffersWithAchievement").clear();
727
        redisShortCacheManager.getCache("todayOffers").clear();
35894 amit 728
        // Evict offer detail (price circular) for added partners; key=(fofoId, offerId), 0=admin
35892 amit 729
        for (Integer fofoId : fofoIds) {
730
            thirtyMinsTimeOutCacheManager.getCache("partnerOffers").evict(new SimpleKey(fofoId, offerId));
731
        }
732
        thirtyMinsTimeOutCacheManager.getCache("partnerOffers").evict(new SimpleKey(0, offerId));
35886 amit 733
 
734
        Map<String, Object> response = new HashMap<>();
735
        response.put("message", "Partner(s) added to Offer #" + offerId + ".");
736
        response.put("yearMonth", ym.toString());
737
        return responseSender.ok(response);
738
    }
739
 
740
    @RequestMapping(value = "/offer/updateTargets", method = RequestMethod.POST)
741
    public ResponseEntity<?> updateOfferTargets(HttpServletRequest request,
742
            @RequestParam int offerId, @RequestParam List<Integer> targets) throws Exception {
743
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
744
        if (!roleManager.isAdmin(loginDetails.getRoleIds())) {
745
            throw new ProfitMandiBusinessException("Unauthorized", "Unauthorized", "");
746
        }
747
        offerService.updateOfferTargets(offerId, targets);
35925 amit 748
        evictOfferCaches(offerId);
749
        return responseSender.ok("Targets updated for Offer #" + offerId);
750
    }
35886 amit 751
 
35925 amit 752
    @RequestMapping(value = "/offer/updateSlabs", method = RequestMethod.POST, consumes = "application/json")
753
    public ResponseEntity<?> updateOfferSlabs(HttpServletRequest request,
754
            @RequestBody com.spice.profitmandi.dao.model.UpdateOfferSlabsRequest updateRequest) throws Exception {
755
        LoginDetails loginDetails = cookiesProcessor.getCookiesObject(request);
756
        if (!roleManager.isAdmin(loginDetails.getRoleIds())) {
757
            throw new ProfitMandiBusinessException("Unauthorized", "Unauthorized", "");
758
        }
759
        offerService.updateOfferSlabs(updateRequest);
760
        evictOfferCaches(updateRequest.getOfferId());
761
        return responseSender.ok("Slabs updated for Offer #" + updateRequest.getOfferId());
762
    }
763
 
764
    private void evictOfferCaches(int offerId) {
35886 amit 765
        Offer offer = offerRepository.selectById(offerId);
766
        YearMonth ym = YearMonth.from(offer.getStartDate());
767
        oneDayCacheManager.getCache("allOffers").evict(ym);
768
        redisCacheManager.getCache("catalog.published_yearmonth").evict(ym);
35925 amit 769
        oneDayCacheManager.getCache("publishedOffersWithAchievement").clear();
770
        redisShortCacheManager.getCache("todayOffers").clear();
35893 amit 771
        PartnerCriteria partnerCriteria = gson.fromJson(offer.getPartnerCriteria(), PartnerCriteria.class);
35892 amit 772
        if (partnerCriteria != null && partnerCriteria.getFofoIds() != null) {
773
            for (Integer fofoId : partnerCriteria.getFofoIds()) {
774
                thirtyMinsTimeOutCacheManager.getCache("partnerOffers").evict(new SimpleKey(fofoId, offerId));
775
            }
776
        }
777
        thirtyMinsTimeOutCacheManager.getCache("partnerOffers").evict(new SimpleKey(0, offerId));
35886 amit 778
    }
779
 
27895 amit.gupta 780
}