Subversion Repositories SmartDukaan

Rev

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

Rev Author Line No. Line
22980 ashik.ali 1
package com.spice.profitmandi.service.user;
2
 
35289 amit 3
import com.fasterxml.jackson.databind.ObjectMapper;
26528 amit.gupta 4
import com.google.common.hash.Hashing;
35289 amit 5
import com.google.gson.Gson;
30097 tejbeer 6
import com.spice.profitmandi.common.enumuration.ActivationType;
7
import com.spice.profitmandi.common.enumuration.FofoType;
22980 ashik.ali 8
import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
30017 amit.gupta 9
import com.spice.profitmandi.common.model.*;
23329 ashik.ali 10
import com.spice.profitmandi.common.util.StringUtils;
11
import com.spice.profitmandi.common.util.Utils;
35418 aman 12
import com.spice.profitmandi.dao.entity.catalog.BrandCatalog;
35203 amit 13
import com.spice.profitmandi.dao.entity.dtr.*;
22980 ashik.ali 14
import com.spice.profitmandi.dao.entity.dtr.User;
30017 amit.gupta 15
import com.spice.profitmandi.dao.entity.fofo.*;
24349 amit.gupta 16
import com.spice.profitmandi.dao.entity.inventory.State;
33124 ranu 17
import com.spice.profitmandi.dao.entity.logistics.AST;
18
import com.spice.profitmandi.dao.entity.logistics.ASTRepository;
30017 amit.gupta 19
import com.spice.profitmandi.dao.entity.user.*;
23063 ashik.ali 20
import com.spice.profitmandi.dao.enumuration.dtr.AccountType;
23106 ashik.ali 21
import com.spice.profitmandi.dao.enumuration.dtr.RetailerType;
23136 ashik.ali 22
import com.spice.profitmandi.dao.enumuration.dtr.RoleType;
23365 ashik.ali 23
import com.spice.profitmandi.dao.enumuration.fofo.PaymentOptionType;
29042 tejbeer 24
import com.spice.profitmandi.dao.enumuration.transaction.PartnerVerificationApprovalStatus;
34813 aman 25
import com.spice.profitmandi.dao.model.LastMonthCreditedIncomeModel;
35203 amit 26
import com.spice.profitmandi.dao.repository.dtr.*;
22980 ashik.ali 27
import com.spice.profitmandi.dao.repository.dtr.UserRepository;
34813 aman 28
import com.spice.profitmandi.dao.repository.fofo.*;
24349 amit.gupta 29
import com.spice.profitmandi.dao.repository.inventory.StateRepository;
35289 amit 30
import com.spice.profitmandi.dao.repository.trialOnboarding.TrialFormRepository;
30017 amit.gupta 31
import com.spice.profitmandi.dao.repository.user.*;
33124 ranu 32
import com.spice.profitmandi.service.PostOfficeService;
35203 amit 33
import com.spice.profitmandi.service.catalog.BrandsService;
23043 ashik.ali 34
import in.shop2020.model.v1.user.CartStatus;
30017 amit.gupta 35
import org.apache.logging.log4j.LogManager;
36
import org.apache.logging.log4j.Logger;
37
import org.springframework.beans.factory.annotation.Autowired;
38
import org.springframework.beans.factory.annotation.Qualifier;
39
import org.springframework.cache.annotation.Cacheable;
35289 amit 40
import org.springframework.mail.javamail.JavaMailSender;
30017 amit.gupta 41
import org.springframework.stereotype.Component;
37156 amit 42
import org.springframework.transaction.annotation.Transactional;
23043 ashik.ali 43
 
30017 amit.gupta 44
import java.nio.charset.StandardCharsets;
34813 aman 45
import java.time.LocalDate;
30017 amit.gupta 46
import java.time.LocalDateTime;
34813 aman 47
import java.time.YearMonth;
48
import java.time.format.DateTimeFormatter;
30017 amit.gupta 49
import java.util.*;
50
import java.util.function.Function;
51
import java.util.stream.Collectors;
52
import java.util.stream.Stream;
53
 
22980 ashik.ali 54
@Component
55
public class RetailerServiceImpl implements RetailerService {
23955 govind 56
 
31734 tejbeer 57
    private static final Logger LOGGER = LogManager.getLogger(RetailerServiceImpl.class);
35289 amit 58
    private static final String[] TRIAL_CODE_CREATION_AUDIENCE = new String[]{"amit.gupta@smartdukaan.com"};
59
    //private static final String [] TRIAL_CODE_CREATION_AUDIENCE = new String[]{};
23955 govind 60
 
31734 tejbeer 61
    @Autowired
62
    private RetailerRepository retailerRepository;
23955 govind 63
 
31734 tejbeer 64
    @Autowired
65
    private RetailerBlockBrandsRepository retailerBlockBrandsRepository;
28024 tejbeer 66
 
31734 tejbeer 67
    @Autowired
68
    private UserAccountRepository userAccountRepository;
23955 govind 69
 
31734 tejbeer 70
    @Autowired
71
    private Mongo mongoClient;
28024 tejbeer 72
 
31734 tejbeer 73
    @Autowired
35289 amit 74
    Gson gson;
75
 
76
    @Autowired
31734 tejbeer 77
    private UserRepository userRepository;
35289 amit 78
    @Autowired
79
    ObjectMapper objectMapper;
23955 govind 80
 
35289 amit 81
 
31734 tejbeer 82
    @Autowired
83
    private CartRepository cartRepository;
23955 govind 84
 
31734 tejbeer 85
    @Autowired
86
    private RetailerRegisteredAddressRepository retailerRegisteredAddressRepository;
23955 govind 87
 
31734 tejbeer 88
    @Autowired
89
    private AddressRepository addressRepository;
23955 govind 90
 
31734 tejbeer 91
    @Autowired
92
    private ShopRepository shopRepository;
23955 govind 93
 
31734 tejbeer 94
    @Autowired
95
    private ShopAddressRepository shopAddressRepository;
23955 govind 96
 
31734 tejbeer 97
    @Autowired
98
    private UserRoleRepository userRoleRepository;
23955 govind 99
 
31734 tejbeer 100
    @Autowired
101
    private DocumentRepository documentRepository;
23955 govind 102
 
31734 tejbeer 103
    @Autowired
32737 amit.gupta 104
    private RetailerContactRepository retailerContactRepository;
105
 
106
    @Autowired
31734 tejbeer 107
    private StateRepository stateRepository;
35289 amit 108
    @Autowired
109
    private TrialFormRepository trialFormRepository;
23955 govind 110
 
31734 tejbeer 111
    @Autowired
112
    @Qualifier("userUserRepository")
113
    private com.spice.profitmandi.dao.repository.user.UserRepository userUserRepository;
23955 govind 114
 
31734 tejbeer 115
    @Autowired
116
    private DistrictMasterRepository districtMasterRepository;
23955 govind 117
 
31734 tejbeer 118
    @Autowired
119
    private FofoStoreRepository fofoStoreRepository;
23955 govind 120
 
31734 tejbeer 121
    @Autowired
33124 ranu 122
    private ASTRepository aSTRepository;
123
 
124
    @Autowired
125
    private PostOfficeService postOfficeService;
126
 
127
    @Autowired
31734 tejbeer 128
    private PaymentOptionRepository paymentOptionRepository;
23955 govind 129
 
31734 tejbeer 130
    @Autowired
131
    private FofoPartnerPaymentOptionRepository fofoPartnerPaymentOptionRepository;
23955 govind 132
 
31734 tejbeer 133
    @Autowired
134
    private RoleRepository roleRepository;
23955 govind 135
 
31734 tejbeer 136
    @Autowired
137
    private StoreTimelineTatService storeTimelineTatService;
28908 tejbeer 138
 
31734 tejbeer 139
    @Autowired
140
    private PartnerOnBoardingPanelRepository partnerOnBoardingPanelRepository;
28908 tejbeer 141
 
31734 tejbeer 142
    @Autowired
143
    private PartnerOnboardingVerificationRepository partnerOnboardingVerificationRepository;
29042 tejbeer 144
 
31734 tejbeer 145
    @Autowired
146
    private PincodePartnerRepository pincodePartnerRepository;
30719 tejbeer 147
 
34813 aman 148
    @Autowired
149
    SchemeInOutRepository schemeInOutRepository;
150
 
151
    @Autowired
152
    OfferPayoutRepository offerPayoutRepository;
153
 
154
    @Autowired
155
    PartnerTypeChangeService partnerTypeChangeService;
156
 
35203 amit 157
    @Autowired
158
    BrandsService brandsService;
35289 amit 159
    @Autowired
160
    private JavaMailSender googleMailSender;
35203 amit 161
 
31734 tejbeer 162
    @Override
163
    public Map<String, Object> getByEmailIdOrMobileNumber(String emailIdOrMobileNumber) throws ProfitMandiBusinessException {
164
        User user = null;
28024 tejbeer 165
 
31734 tejbeer 166
        try {
167
            user = userRepository.selectByEmailIdOrMobileNumber(emailIdOrMobileNumber);
168
        } catch (ProfitMandiBusinessException profitMandiBusinessException) {
23955 govind 169
 
31734 tejbeer 170
        }
171
        if (user == null) {
172
            try {
173
                user = userRepository.selectBySecondryEmailId(emailIdOrMobileNumber);
174
            } catch (ProfitMandiBusinessException profitMandiBusinessException) {
23955 govind 175
 
31734 tejbeer 176
            }
177
        }
178
        Map<String, Object> map = new HashMap<>();
35394 amit 179
        map.put("stateNames", stateRepository.selectAll().stream().map(State::getName).collect(Collectors.toList()));
35289 amit 180
        LOGGER.info("user - {}", user);
31734 tejbeer 181
        if (user != null) {
23955 govind 182
 
31734 tejbeer 183
            List<UserRole> userRoles = userRoleRepository.selectByUserId(user.getId());
23955 govind 184
 
31734 tejbeer 185
            Role role = roleRepository.selectByName(RoleType.FOFO.toString());
23955 govind 186
 
31734 tejbeer 187
            map.put("userRoles", userRoles);
188
            map.put("user", user);
189
            // map.put("retailer", retailer);
190
            map.put("fofoRole", this.containsRoleType(userRoles, role.getId()));
23955 govind 191
 
31734 tejbeer 192
            map.put("userRoleNames", this.toString(userRoles));
193
            try {
194
                int retailerId = userAccountRepository.selectRetailerIdByUserId(user.getId());
195
                Retailer retailer = retailerRepository.selectById(retailerId);
23955 govind 196
 
31734 tejbeer 197
                map.put("retailer", retailer);
23955 govind 198
 
37102 amit 199
                // This screen edits manual brand blocks only. Ineligibility (commitment/DMS) is
200
                // derived and enforced at order time, so the dropdown offers every brand.
201
                Set<String> brands = brandsService.getBrandsToDisplay(3).stream()
202
                        .map(BrandCatalog::getName).collect(Collectors.toSet());
203
                List<String> retailerBlockBrands = retailerBlockBrandsRepository.selectAllByRetailer(retailer.getId())
204
                        .stream().map(x -> x.getBlockBrands()).collect(Collectors.toList());
31734 tejbeer 205
                map.put("brands", brands);
206
                map.put("retailerBlockBrands", retailerBlockBrands);
23955 govind 207
 
31734 tejbeer 208
                try {
35896 amit 209
                    FofoStore gstStore = fofoStoreRepository.selectByRetailerId(retailer.getId());
210
                    map.put("gstNumber", gstStore != null ? gstStore.getGstNumber() : null);
211
                } catch (ProfitMandiBusinessException e) {
212
                    LOGGER.error("FofoStore not found for GST lookup");
31734 tejbeer 213
                }
214
                try {
215
                    int retailerAddressId = retailerRegisteredAddressRepository.selectAddressIdByRetailerId(retailer.getId());
216
                    Address retailerAddress = addressRepository.selectById(retailerAddressId);
217
                    map.put("retailerAddress", retailerAddress);
218
                    State state = stateRepository.selectByName(retailerAddress.getState());
219
                    // LOGGER.info("retailerAddress.." + retailerAddress);
220
                    List<DistrictMaster> districtMasters = districtMasterRepository.selectByStateShortName(state.getShortName());
221
                    map.put("districtMasters", districtMasters);
222
                    // LOGGER.info("districtMasters" + districtMasters);
223
                    List<Shop> shops = shopRepository.selectByRetailerId(retailer.getId());
224
                    map.put("shops", shops);
225
                    this.addAddress(shops);
33128 amit.gupta 226
 
227
                    if (this.containsRoleType(userRoles, role.getId())) {
228
                        try {
229
                            FofoStore fofoStore = fofoStoreRepository.selectByRetailerId(retailerId);
230
                            map.put("fofoStore", fofoStore);
231
                            List<AST> astDetail = postOfficeService.getAreasAndTerritoriesByStateName(retailerAddress.getState());
232
                            LOGGER.info("astDetail {}", astDetail);
233
                            map.put("astDetail", astDetail);
234
 
235
 
236
                            // map.put("counterSize", fofoStore.getCounterSize().toString());
237
                            // LOGGER.info("fofoStore" + fofoStore);
238
                        } catch (ProfitMandiBusinessException profitMandiBusinessException) {
239
                            LOGGER.error("FofoStore code not found");
240
                        }
241
                    }
31734 tejbeer 242
                    // LOGGER.info("shops" + shops);
243
                } catch (ProfitMandiBusinessException profitMandiBusinessException) {
244
                    LOGGER.error("Retailer Registered Address not found");
245
                }
246
            } catch (ProfitMandiBusinessException profitMandiBusinessException) {
247
                LOGGER.error("Retailer not found in user_account");
248
            }
35289 amit 249
        } else {
250
            try {
251
                TrialForm trialForm = trialFormRepository.selectByEmailOrMobile(emailIdOrMobileNumber);
35372 aman 252
                LOGGER.info("trialForm - {}", trialForm);
35289 amit 253
                map.put("trialForm", gson.toJson(trialForm));
254
            } catch (Exception e) {
255
                LOGGER.error("Retailer not found in user_account");
256
            }
31734 tejbeer 257
        }
23955 govind 258
 
31734 tejbeer 259
        return map;
260
    }
23955 govind 261
 
31734 tejbeer 262
    private boolean containsRoleType(List<UserRole> userRoles, int roleId) {
35394 amit 263
        return userRoles != null && userRoles.stream().anyMatch(ur -> ur.getRoleId() == roleId);
31734 tejbeer 264
    }
23955 govind 265
 
31734 tejbeer 266
    private List<UserRole> addRole(List<UserRole> userRoles, int userId, int roleId) {
267
        if (userRoles == null) {
268
            userRoles = new ArrayList<>();
269
        }
270
        if (!this.containsRoleType(userRoles, roleId)) {
271
            UserRole userRole = new UserRole();
272
            userRole.setUserId(userId);
273
            userRole.setRoleId(roleId);
274
            try {
275
                userRoleRepository.persist(userRole);
276
            } catch (ProfitMandiBusinessException e) {
277
                LOGGER.error("UserRole is already exist");
278
            }
279
            userRoles.add(userRole);
280
        }
281
        return userRoles;
23955 govind 282
 
31734 tejbeer 283
    }
23955 govind 284
 
31734 tejbeer 285
    private List<UserRole> removeRole(List<UserRole> userRoles, int userId, int roleId) {
286
        if (userRoles == null) {
287
            userRoles = new ArrayList<>();
288
            return userRoles;
289
        }
290
        try {
291
            userRoles.remove(userRoleRepository.deleteByRoleUserId(userId, roleId));
292
        } catch (Exception e) {
25295 amit.gupta 293
 
31734 tejbeer 294
        }
295
        return userRoles;
25295 amit.gupta 296
 
31734 tejbeer 297
    }
25295 amit.gupta 298
 
31734 tejbeer 299
    @SuppressWarnings("unchecked")
300
    @Override
37156 amit 301
    @Transactional(rollbackFor = Throwable.class)
33128 amit.gupta 302
    public Map<String, Object> updateRetailerDetails(UpdateRetailerRequest updateRetailerRequest) throws
303
            ProfitMandiBusinessException {
37669 amit 304
        this.validateGstNumbers(updateRetailerRequest);
305
 
31734 tejbeer 306
        Map<String, Object> map = this.getByEmailIdOrMobileNumber(updateRetailerRequest.getEmailIdOrMobileNumber());
32953 amit.gupta 307
        User dtrUser = (User) map.get("user");
28024 tejbeer 308
 
37156 amit 309
        if (updateRetailerRequest.isFofo()) {
310
            Retailer resolvedRetailer = (Retailer) map.get("retailer");
311
            if (resolvedRetailer == null) {
312
                // This save would mint a brand-new identity chain. Mandate: a partner
313
                // gets a new store code only after the old store is closed, and the
314
                // re-onboarding must reuse the partner's real email (takeover below) —
315
                // never a variant email that forks a duplicate chain.
316
                this.guardAgainstDuplicatePartnerChain(updateRetailerRequest);
317
            } else if (updateRetailerRequest.isActive()) {
318
                FofoStore existingStore = this.selectStoreOrNull(resolvedRetailer.getId());
319
                if (existingStore != null && existingStore.isClosed()) {
320
                    this.takeoverClosedStoreIdentity(existingStore, map);
321
                }
322
            }
323
        }
324
 
32953 amit.gupta 325
        dtrUser = this.createUser(dtrUser, updateRetailerRequest);
28024 tejbeer 326
 
32953 amit.gupta 327
        map.put("user", dtrUser);
31734 tejbeer 328
        List<UserRole> userRoles = (List<UserRole>) map.get("userRoles");
329
        Role roleUser = roleRepository.selectByName(RoleType.USER.toString());
32953 amit.gupta 330
        userRoles = this.addRole(userRoles, dtrUser.getId(), roleUser.getId());
31734 tejbeer 331
        Retailer retailer = (Retailer) map.get("retailer");
32953 amit.gupta 332
        retailer = this.updateRetailer(dtrUser, retailer, updateRetailerRequest);
28024 tejbeer 333
 
31734 tejbeer 334
        map.put("retailer", retailer);
23955 govind 335
 
37156 amit 336
        // Ensure the dtr login's bridge rows point at the current identity. Repairs
337
        // recreated logins and repoints the login after a closed-store takeover.
338
        userAccountRepository.upsert(dtrUser.getId(), AccountType.saholic, retailer.getId());
35971 aman 339
        try {
37156 amit 340
            com.spice.profitmandi.dao.entity.user.User identity = userUserRepository.selectById(retailer.getId());
341
            if (identity.getActiveCartId() > 0) {
342
                userAccountRepository.upsert(dtrUser.getId(), AccountType.cartId, identity.getActiveCartId());
343
            }
35971 aman 344
        } catch (ProfitMandiBusinessException e) {
37156 amit 345
            LOGGER.error("Error ensuring cartId UserAccount for userId: {}", dtrUser.getId(), e);
35971 aman 346
        }
347
 
31734 tejbeer 348
        List<String> retailerBlockBrands = retailerBlockBrandsRepository.selectAllByRetailer(retailer.getId()).stream().map(x -> x.getBlockBrands()).collect(Collectors.toList());
28024 tejbeer 349
 
31734 tejbeer 350
        LOGGER.info("retailerBlockBrands" + retailerBlockBrands);
28189 tejbeer 351
 
31734 tejbeer 352
        if (!retailerBlockBrands.isEmpty()) {
353
            retailerBlockBrandsRepository.deleteBrands(retailer.getId());
354
        }
28024 tejbeer 355
 
37102 amit 356
        List<String> requestedBlockBrands = updateRetailerRequest.getBlocksBrands() != null
357
                ? updateRetailerRequest.getBlocksBrands() : new ArrayList<>();
358
 
359
        for (String blockBrand : requestedBlockBrands) {
31734 tejbeer 360
            RetailerBlockBrands retailerBlockBrand = new RetailerBlockBrands();
28024 tejbeer 361
 
31734 tejbeer 362
            retailerBlockBrand.setFofoId(retailer.getId());
363
            retailerBlockBrand.setBlockBrands(blockBrand);
364
            retailerBlockBrandsRepository.persist(retailerBlockBrand);
28024 tejbeer 365
 
31734 tejbeer 366
        }
367
        map.put("retailerBlockBrands", retailerBlockBrands);
28024 tejbeer 368
 
31734 tejbeer 369
        Role roleRetailer = roleRepository.selectByName(RoleType.RETAILER.toString());
23955 govind 370
 
32953 amit.gupta 371
        userRoles = this.addRole(userRoles, dtrUser.getId(), roleRetailer.getId());
23955 govind 372
 
31734 tejbeer 373
        Role roleFofo = roleRepository.selectByName(RoleType.FOFO.toString());
23955 govind 374
 
31734 tejbeer 375
        if (updateRetailerRequest.isFofo()) {
32953 amit.gupta 376
            userRoles = this.addRole(userRoles, dtrUser.getId(), roleFofo.getId());
31734 tejbeer 377
        } else {
32953 amit.gupta 378
            userRoles = this.removeRole(userRoles, dtrUser.getId(), roleFofo.getId());
31734 tejbeer 379
        }
380
        map.put("fofoRole", this.containsRoleType(userRoles, roleFofo.getId()));
23955 govind 381
 
31734 tejbeer 382
        if (this.containsRoleType(userRoles, roleFofo.getId())) {
383
            this.createDefaultPaymentOption(retailer.getId());
384
        }
23955 govind 385
 
31734 tejbeer 386
        map.put("userRoles", userRoles);
387
        map.put("userRoleNames", this.toString(userRoles));
23955 govind 388
 
31734 tejbeer 389
        Address retailerAddress = (Address) map.get("retailerAddress");
390
        retailerAddress = this.updateRetailerAddress(retailerAddress, updateRetailerRequest.getAddress(), retailer.getId());
391
        map.put("retailerAddress", retailerAddress);
23955 govind 392
 
31734 tejbeer 393
        if (updateRetailerRequest.isFofo()) {
394
            FofoStore fofoStore = this.createFofoStoreCodeByRetailerId(retailer.getId(), updateRetailerRequest.getDistrictName(), retailerAddress.getState(), updateRetailerRequest);
395
            map.put("fofoStore", fofoStore);
35956 amit 396
            if (fofoStore.isClosed() && updateRetailerRequest.isActive()) {
397
                throw new ProfitMandiBusinessException("Store Closed", "Store Permanently Closed",
398
                        "This store is permanently closed and cannot be reactivated");
399
            }
31734 tejbeer 400
            fofoStore.setActive(updateRetailerRequest.isActive());
33131 ranu 401
            List<AST> astDetail = postOfficeService.getAreasAndTerritoriesByStateName(retailerAddress.getState());
402
            map.put("astDetail", astDetail);
31734 tejbeer 403
        }
23955 govind 404
 
31734 tejbeer 405
        map.put("gstNumber", updateRetailerRequest.getGstNumber());
406
        this.updateSaholicUser(retailer.getId(), retailerAddress.getId());
23955 govind 407
 
31734 tejbeer 408
        List<Shop> shops = (List<Shop>) map.get("shops");
409
        if (shops == null) {
410
            shops = new ArrayList<>();
411
            map.put("shops", shops);
412
        }
413
        this.updateRetailerShops(shops, updateRetailerRequest.getShops(), retailer.getId(), retailerAddress);
23955 govind 414
 
31734 tejbeer 415
        return map;
23955 govind 416
 
31734 tejbeer 417
    }
23955 govind 418
 
37156 amit 419
    private FofoStore selectStoreOrNull(int retailerId) {
420
        try {
421
            return fofoStoreRepository.selectByRetailerId(retailerId);
422
        } catch (ProfitMandiBusinessException e) {
423
            return null;
424
        }
425
    }
426
 
37669 amit 427
    /**
428
     * The onboarding screen carries the partner's GSTIN in two boxes that both read "GST NUMBER":
429
     * the retailer one (dtr.retailer.number) and the store one (fofo_store.gst_number, which is
430
     * what billing reads and what goes to NIC as the recipient). Neither was validated, so
431
     * DLSH1660 was saved with the LOI's pincode (110095) in the store box while the retailer box
432
     * held the real 07CMEPR1110C1ZO - an invoice NIC would refuse.
433
     * <p>
434
     * Both are normalised and checked here, before any write, and must agree when both are
435
     * present: across 1,800 partners on record they already do, bar the one that caused this.
436
     */
437
    private void validateGstNumbers(UpdateRetailerRequest updateRetailerRequest)
438
            throws ProfitMandiBusinessException {
439
        String storeGstin = StringUtils.normalizeGstNumber(updateRetailerRequest.getGstNumber());
440
        String retailerGstin = StringUtils.normalizeGstNumber(updateRetailerRequest.getNumber());
441
 
442
        if (!StringUtils.isValidGstNumber(storeGstin)) {
443
            throw new ProfitMandiBusinessException("gstNumber", storeGstin, "RTLR_1020");
444
        }
445
        if (!StringUtils.isValidGstNumber(retailerGstin)) {
446
            throw new ProfitMandiBusinessException("number", retailerGstin, "RTLR_1020");
447
        }
448
        if (isNotBlank(storeGstin) && isNotBlank(retailerGstin) && !storeGstin.equals(retailerGstin)) {
449
            throw new ProfitMandiBusinessException("gstNumber", storeGstin + " / " + retailerGstin, "RTLR_1021");
450
        }
451
 
452
        // Persist what was validated, so the same registration is never stored two ways.
453
        updateRetailerRequest.setGstNumber(storeGstin);
454
        updateRetailerRequest.setNumber(retailerGstin);
455
    }
456
 
457
    private static boolean isNotBlank(String value) {
458
        return value != null && !value.isEmpty();
459
    }
460
 
37156 amit 461
    private void guardAgainstDuplicatePartnerChain(UpdateRetailerRequest updateRetailerRequest)
462
            throws ProfitMandiBusinessException {
463
        User byMobile = null;
464
        try {
465
            byMobile = userRepository.selectByMobileNumber(updateRetailerRequest.getUserMobileNumber());
466
        } catch (ProfitMandiBusinessException e) {
467
            // no dtr user with this mobile
468
        }
469
        if (byMobile != null) {
470
            Integer accountKey = userAccountRepository.selectSaholicAccountKeySafe(byMobile.getId());
471
            FofoStore store = accountKey != null ? this.selectStoreOrNull(accountKey) : null;
472
            if (store != null) {
473
                if (!store.isClosed()) {
474
                    throw new ProfitMandiBusinessException("Open store exists", store.getCode(),
475
                            "Partner mobile " + updateRetailerRequest.getUserMobileNumber()
476
                                    + " already owns open store " + store.getCode()
477
                                    + ". Close it first, or use email-change to keep the same code.");
478
                }
479
                throw new ProfitMandiBusinessException("Closed store exists", store.getCode(),
480
                        "Old store " + store.getCode() + " is closed. Re-onboard using the partner's existing email "
481
                                + byMobile.getEmailId() + " and a new code will be issued automatically.");
482
            }
483
        }
37168 amit 484
        // Same GST is normal (one GSTIN per entity per state; parallel outlets share it).
485
        // Block only when a sibling store is in limbo: dormant (REVIVAL) or deactivated
486
        // without being closed — the signature of a revival being forked instead of the
487
        // old code being closed or revived in place.
488
        List<FofoStore> limboGstStores = fofoStoreRepository.selectAllOpenByGstNumber(updateRetailerRequest.getGstNumber())
489
                .stream()
490
                .filter(s -> !s.isInternal())
491
                .filter(s -> s.getActivationType() == ActivationType.REVIVAL || !s.isActive())
492
                .collect(Collectors.toList());
493
        if (!limboGstStores.isEmpty()) {
494
            String codes = limboGstStores.stream().map(FofoStore::getCode).collect(Collectors.joining(", "));
495
            throw new ProfitMandiBusinessException("Dormant store exists for GST", codes,
496
                    "GST " + updateRetailerRequest.getGstNumber() + " has store(s) " + codes
497
                            + " that are dormant or deactivated but not closed. Close them or revive them on the same code before creating a new store.");
37156 amit 498
        }
499
    }
500
 
501
    private void takeoverClosedStoreIdentity(FofoStore oldStore, Map<String, Object> map) {
502
        // Mandate: closed stores are never reopened. Re-onboarding with the partner's
503
        // real contacts issues a fresh code on the same dtr login: free the old
504
        // identity's email so the new user.user can take it over, then drop the old
505
        // chain from the resolution map so the save proceeds as a fresh onboarding.
506
        try {
507
            com.spice.profitmandi.dao.entity.user.User oldIdentity = userUserRepository.selectById(oldStore.getId());
508
            String tombstone = "closed." + oldStore.getId() + "." + oldIdentity.getEmailId();
509
            if (tombstone.length() > 128) {
510
                tombstone = tombstone.substring(0, 128);
511
            }
512
            oldIdentity.setEmailId(tombstone);
513
        } catch (ProfitMandiBusinessException e) {
514
            LOGGER.error("Takeover: identity not found for closed store {}", oldStore.getId(), e);
515
        }
516
        LOGGER.info("Takeover: closed store {} ({}) — issuing new code on the same login", oldStore.getCode(), oldStore.getId());
517
        map.remove("retailer");
518
        map.remove("retailerAddress");
519
        map.remove("shops");
520
        map.remove("fofoStore");
521
    }
522
 
31734 tejbeer 523
    private void createDefaultPaymentOption(int fofoId) {
524
        List<Integer> paymentOptionIds = fofoPartnerPaymentOptionRepository.selectPaymentOptionIdsByFofoId(fofoId);
525
        if (paymentOptionIds.isEmpty()) {
526
            PaymentOption paymentOption = null;
527
            try {
528
                paymentOption = paymentOptionRepository.selectByName(PaymentOptionType.CASH.toString());
529
            } catch (ProfitMandiBusinessException profitMandiBusinessException) {
530
                paymentOption = new PaymentOption();
531
                paymentOption.setName(PaymentOptionType.CASH.toString());
532
                paymentOptionRepository.persist(paymentOption);
533
            }
534
            FofoPartnerPaymentOption fofoPartnerPaymentOption = new FofoPartnerPaymentOption();
535
            fofoPartnerPaymentOption.setFofoId(fofoId);
536
            fofoPartnerPaymentOption.setPaymentOptionId(paymentOption.getId());
537
            fofoPartnerPaymentOptionRepository.persist(fofoPartnerPaymentOption);
538
        }
23955 govind 539
 
31734 tejbeer 540
    }
23955 govind 541
 
33128 amit.gupta 542
    private User createUser(User user, UpdateRetailerRequest updateRetailerRequest) throws
543
            ProfitMandiBusinessException {
32965 amit.gupta 544
 
545
        User dtrUser = null;
546
        try {
547
            dtrUser = userRepository.selectByMobileNumber(updateRetailerRequest.getUserMobileNumber());
548
        } catch (ProfitMandiBusinessException e) {
549
            //Ignore the exception
550
        }
33140 ranu 551
        if (dtrUser != null && (user == null || user.getId() != dtrUser.getId()))
552
            throw new ProfitMandiBusinessException("Mobile already exist", updateRetailerRequest.getUserMobileNumber(), dtrUser.getEmailId());
32966 amit.gupta 553
 
554
        User dtrUserByEmail = null;
555
        try {
556
            dtrUserByEmail = userRepository.selectByEmailId(updateRetailerRequest.getUserEmailId());
557
        } catch (ProfitMandiBusinessException e) {
558
            //ignore the exception
559
        }
33025 amit.gupta 560
        if (user != null && dtrUserByEmail != null && user.getId() != dtrUserByEmail.getId())
32965 amit.gupta 561
            throw new ProfitMandiBusinessException("Email already exist", updateRetailerRequest.getUserEmailId(), "");
32953 amit.gupta 562
 
563
 
31734 tejbeer 564
        if (user == null) {
565
            user = new User();
566
            user.setCity("");
567
            user.setPinCode(0);
568
            user.setState("");
569
            user.setPassword("");
570
            user.setMobile_verified(false);
571
            user.setReferral_url("");
572
            user.setGroup_id(1);
573
            user.setStatus(1);
574
            user.setActivated(true);
575
            user.setCreateTimestamp(LocalDateTime.now());
576
        }
577
        user.setActivated(updateRetailerRequest.isActive());
578
        user.setFirstName(updateRetailerRequest.getUserFirstName());
579
        user.setLastName(updateRetailerRequest.getUserLastName());
580
        user.setMobileNumber(updateRetailerRequest.getUserMobileNumber());
581
        user.setEmailId(updateRetailerRequest.getUserEmailId());
582
        user.setUsername(updateRetailerRequest.getUserEmailId());
583
        user.setUpdateTimestamp(LocalDateTime.now());
584
        userRepository.persist(user);
585
        return user;
23955 govind 586
 
31734 tejbeer 587
    }
23955 govind 588
 
31734 tejbeer 589
    private int createSaholicUser(User user, String retailerName) {
590
        com.spice.profitmandi.dao.entity.user.User saholicUser = null;
591
        try {
592
            saholicUser = userUserRepository.selectByEmailId(user.getEmailId());
593
        } catch (ProfitMandiBusinessException e) {
594
            LOGGER.info("User doesnt exist in old system");
595
        }
596
        if (saholicUser == null) {
597
            Cart cart = new Cart();
598
            cart.setCartStatus(CartStatus.ACTIVE);
599
            cartRepository.persist(cart);
600
            saholicUser = new com.spice.profitmandi.dao.entity.user.User();
601
            saholicUser.setEmailId(user.getEmailId());
602
            saholicUser.setName(retailerName);
603
            saholicUser.setActiveCartId(cart.getId());
604
            saholicUser.setCreateTimestamp(LocalDateTime.now());
605
            userUserRepository.persist(saholicUser);
23955 govind 606
 
37156 amit 607
            userAccountRepository.upsert(user.getId(), AccountType.saholic, saholicUser.getId());
608
            userAccountRepository.upsert(user.getId(), AccountType.cartId, saholicUser.getActiveCartId());
31734 tejbeer 609
            LOGGER.info("created....");
610
        }
611
        return saholicUser.getId();
612
    }
23955 govind 613
 
31734 tejbeer 614
    private com.spice.profitmandi.dao.entity.user.User createSaholicUser(
32953 amit.gupta 615
            LoginRequestResponseModel loginRequestResponseModel) {
31734 tejbeer 616
        com.spice.profitmandi.dao.entity.user.User saholicUser = null;
617
        try {
618
            saholicUser = userUserRepository.selectByEmailId(loginRequestResponseModel.getEmail());
619
            saholicUser.setCreateTimestamp(LocalDateTime.now());
620
        } catch (ProfitMandiBusinessException e) {
621
            LOGGER.info("User doesnt exist in old system");
622
        }
623
        if (saholicUser == null) {
624
            Cart cart = new Cart();
625
            cart.setCartStatus(CartStatus.ACTIVE);
626
            cartRepository.persist(cart);
627
            saholicUser = new com.spice.profitmandi.dao.entity.user.User();
628
            saholicUser.setPassword(getHash256(loginRequestResponseModel.getPassword()));
629
            saholicUser.setEmailId(loginRequestResponseModel.getEmail());
630
            saholicUser.setName(loginRequestResponseModel.getCustomerName());
631
            saholicUser.setActiveCartId(cart.getId());
632
            saholicUser.setCreateTimestamp(LocalDateTime.now());
633
            loginRequestResponseModel.setPassword(null);
634
            userUserRepository.persist(saholicUser);
635
        }
636
        return saholicUser;
637
    }
26522 amit.gupta 638
 
33128 amit.gupta 639
    private Retailer updateRetailer(User user, Retailer retailer, UpdateRetailerRequest updateRetailerRequest) throws
640
            ProfitMandiBusinessException {
31734 tejbeer 641
        if (retailer == null) {
642
            LOGGER.info("createSaholicUser.....");
643
            int saholicUserId = this.createSaholicUser(user, updateRetailerRequest.getName());
644
            retailer = new Retailer();
645
            retailer.setId(saholicUserId);
646
        }
647
        retailer.setActive(updateRetailerRequest.isActive());
648
        user.setActivated(updateRetailerRequest.isActive());//
649
        // this.createRole(user.getId(), RoleType.RETAILER);
650
        retailer.setName(updateRetailerRequest.getName());
651
        retailer.setNumber(updateRetailerRequest.getNumber());
652
        if (updateRetailerRequest.getNumber() == null || updateRetailerRequest.getNumber().isEmpty()) {
653
            retailer.setType(RetailerType.UNREGISTERED_SHOP);
654
        } else {
655
            retailer.setType(RetailerType.GSTIN);
656
        }
657
        if (updateRetailerRequest.getDocumentId() > 0) {
658
            if (retailer.getDocumentId() != null && retailer.getDocumentId() != updateRetailerRequest.getDocumentId()) {
659
                try {
660
                    documentRepository.deleteById(retailer.getDocumentId());
661
                } catch (Exception e) {
662
                    e.printStackTrace();
663
                }
664
            }
665
            retailer.setDocumentId(updateRetailerRequest.getDocumentId());
666
            documentRepository.markDocumentAsPersisted(updateRetailerRequest.getDocumentId());
667
        }
668
        retailerRepository.persist(retailer);
669
        return retailer;
670
    }
23955 govind 671
 
31734 tejbeer 672
    private void updateSaholicUser(int retailerId, int retailerAddressId) {
673
        try {
674
            com.spice.profitmandi.dao.entity.user.User user = userUserRepository.selectById(retailerId);
675
            user.setAddressId(retailerAddressId);
32555 amit.gupta 676
            Cart cart = cartRepository.selectById(user.getActiveCartId());
677
            cart.setAddressId(retailerAddressId);
31734 tejbeer 678
        } catch (ProfitMandiBusinessException e) {
23955 govind 679
 
31734 tejbeer 680
        }
681
    }
23955 govind 682
 
33128 amit.gupta 683
    private Address updateRetailerAddress(Address address, CustomAddress customAddress, int retailerId) throws
684
            ProfitMandiBusinessException {
31734 tejbeer 685
        if (address == null) {
35971 aman 686
            // Try to find existing address via RetailerRegisteredAddress (handles case where
687
            // dtr.user was deleted but retailer/address still exist in database)
688
            try {
689
                int existingAddressId = retailerRegisteredAddressRepository.selectAddressIdByRetailerId(retailerId);
690
                address = addressRepository.selectById(existingAddressId);
691
            } catch (ProfitMandiBusinessException e) {
692
                // No existing address found for this retailer
693
            }
23955 govind 694
 
35971 aman 695
            if (address != null) {
696
                // Existing address found - update it
697
                this.updateAddress(address, customAddress);
698
                RetailerRegisteredAddress retailerRegisteredAddress = retailerRegisteredAddressRepository.selectByRetailerId(retailerId);
699
                retailerRegisteredAddress.setAddressId(address.getId());
700
                retailerRegisteredAddressRepository.persist(retailerRegisteredAddress);
701
            } else {
702
                // Truly new address
703
                address = new Address();
704
                address.setRetaierId(retailerId);
705
                this.updateAddress(address, customAddress);
706
 
707
                final RetailerRegisteredAddress retailerRegisteredAddress = new RetailerRegisteredAddress();
708
                retailerRegisteredAddress.setRetailerId(retailerId);
709
                retailerRegisteredAddress.setAddressId(address.getId());
710
                retailerRegisteredAddressRepository.persist(retailerRegisteredAddress);
711
            }
31734 tejbeer 712
        } else {
713
            this.updateAddress(address, customAddress);
714
            RetailerRegisteredAddress retailerRegisteredAddress = retailerRegisteredAddressRepository.selectByRetailerId(retailerId);
715
            retailerRegisteredAddress.setAddressId(address.getId());
716
            retailerRegisteredAddressRepository.persist(retailerRegisteredAddress);
717
        }
718
        return address;
719
    }
23955 govind 720
 
31734 tejbeer 721
    private void updateAddress(Address address, CustomAddress customAddress) throws ProfitMandiBusinessException {
722
        address.setName(customAddress.getName());
723
        address.setPhoneNumber(customAddress.getPhoneNumber());
724
        address.setLine1(customAddress.getLine1());
725
        address.setLine2(customAddress.getLine2());
726
        address.setCity(customAddress.getCity());
727
        address.setPinCode(customAddress.getPinCode());
728
        State state = stateRepository.selectByName(customAddress.getState());
729
        if (state == null) {
730
            throw new ProfitMandiBusinessException("State name", "Invalid State - Pls Contact Technology", "Invalid State - Pls Contact Technology");
731
        }
732
        address.setState(state.getName());
733
        addressRepository.persist(address);
734
        LOGGER.info("Address Updated" + address);
735
    }
23955 govind 736
 
33128 amit.gupta 737
    private void updateRetailerShops(List<Shop> shops, Set<CustomShop> customShops, int retailerId, Address
738
            sameAsRetailerAddressValue) throws ProfitMandiBusinessException {
31734 tejbeer 739
        if (shops.isEmpty()) {
740
            for (CustomShop customShop : customShops) {
741
                Shop shop = new Shop();
742
                this.createOrUpdateShop(shop, customShop, retailerId, sameAsRetailerAddressValue);
743
                shops.add(shop);
744
            }
745
        } else {
746
            for (Shop shop : shops) {
747
                for (CustomShop customShop : customShops) {
748
                    if (shop.getId() == customShop.getShopId()) {
749
                        this.createOrUpdateShop(shop, customShop, retailerId, sameAsRetailerAddressValue);
750
                    }
751
                }
752
            }
753
            for (CustomShop customShop : customShops) {
754
                if (customShop.getShopId() == 0) {
755
                    Shop shop = new Shop();
756
                    this.createOrUpdateShop(shop, customShop, retailerId, sameAsRetailerAddressValue);
757
                    shops.add(shop);
758
                }
759
            }
760
        }
761
    }
23955 govind 762
 
33128 amit.gupta 763
    private void createOrUpdateShop(Shop shop, CustomShop customShop, int retailerId, Address
764
            sameAsRetailerAddressValue) throws ProfitMandiBusinessException {
31734 tejbeer 765
        shop.setRetailerId(retailerId);
766
        shop.setName(customShop.getName());
767
        if (customShop.getDocumentId() > 0) {
768
            if (shop.getDocumentId() != null && shop.getDocumentId() != customShop.getDocumentId()) {
769
                try {
770
                    documentRepository.deleteById(shop.getDocumentId());
771
                } catch (Exception e) {
772
                    e.printStackTrace();
773
                }
774
            }
775
            shop.setDocumentId(customShop.getDocumentId());
776
            documentRepository.markDocumentAsPersisted(customShop.getDocumentId());
777
        }
778
        if (shop.getAddressId() == null) {
779
            Address address = null;
780
            if (customShop.isSameAsRetailerAddress()) {
781
                address = sameAsRetailerAddressValue;
782
            } else {
783
                // shop.setDocumentId(customShop.getDocumentId());
784
                address = new Address();
785
                this.updateAddress(address, customShop.getAddress());
786
            }
787
            shop.setAddressId(address.getId());
788
            shop.setAddress(address);
789
            shopRepository.persist(shop);
790
            ShopAddress shopAddress = null;
791
            try {
792
                shopAddress = shopAddressRepository.selectByShopId(shop.getId());
793
                shopAddress.setAddressId(address.getId());
794
            } catch (ProfitMandiBusinessException profitMandiBusinessException) {
795
                shopAddress = new ShopAddress();
796
                shopAddress.setAddressId(address.getId());
797
                shopAddress.setShopId(shop.getId());
798
            }
799
            shopAddressRepository.persist(shopAddress);
800
        } else {
801
            Address address = null;
802
            try {
803
                address = addressRepository.selectById(shop.getAddressId());
804
                CustomAddress customAddress = customShop.getAddress();
805
                if (!(address.getName().equals(customAddress.getName()) && address.getLine1().equals(customAddress.getLine1()) && address.getLine2().equals(customAddress.getLine2()) && address.getCity().equals(customAddress.getCity()) && address.getPinCode().equals(customAddress.getPinCode()) && address.getState().equals(customAddress.getState()))) {
806
                    address = new Address();
807
                    ShopAddress shopAddress = shopAddressRepository.selectByShopId(shop.getId());
808
                    this.updateAddress(address, customAddress);
809
                    shopAddress.setAddressId(address.getId());
810
                    shopAddressRepository.persist(shopAddress);
811
                    shop.setAddress(address);
812
                    shopRepository.persist(shop);
813
                }
814
            } catch (Exception e) {
815
                if (customShop.isSameAsRetailerAddress()) {
816
                    address = sameAsRetailerAddressValue;
817
                } else {
818
                    // shop.setDocumentId(customShop.getDocumentId());
819
                    address = new Address();
820
                    this.updateAddress(address, customShop.getAddress());
821
                }
822
                shop.setAddressId(address.getId());
823
                shop.setAddress(address);
824
                shopRepository.persist(shop);
825
                ShopAddress shopAddress = null;
826
                try {
827
                    shopAddress = shopAddressRepository.selectByShopId(shop.getId());
828
                    shopAddress.setAddressId(address.getId());
829
                } catch (ProfitMandiBusinessException profitMandiBusinessException) {
830
                    shopAddress = new ShopAddress();
831
                    shopAddress.setAddressId(address.getId());
832
                    shopAddress.setShopId(shop.getId());
833
                }
834
                shopAddressRepository.persist(shopAddress);
835
            }
23955 govind 836
 
31734 tejbeer 837
        }
23955 govind 838
 
31734 tejbeer 839
    }
23955 govind 840
 
33247 ranu 841
    private void addAddress(List<Shop> shops) throws ProfitMandiBusinessException {
31734 tejbeer 842
        Set<Integer> shopIds = this.toShopIds(shops);
843
        if (shopIds.isEmpty()) {
844
            return;
845
        }
846
        List<ShopAddress> shopAddresses = shopAddressRepository.selectByShopIds(shopIds);
847
        Map<Integer, Address> addressIdAddressMap = this.toAddressIdAddressMap(shopAddresses);
23955 govind 848
 
31734 tejbeer 849
        for (Shop shop : shops) {
850
            shop.setAddress(addressIdAddressMap.get(shop.getAddressId()));
851
        }
852
    }
22980 ashik.ali 853
 
33247 ranu 854
    private Map<Integer, Address> toAddressIdAddressMap(List<ShopAddress> shopAddresses) throws ProfitMandiBusinessException {
31734 tejbeer 855
        Map<Integer, Address> addressIdAddressMap = new HashMap<>();
856
        List<Integer> addressIds = this.toAddressIds(shopAddresses);
857
        List<Address> addresses = addressRepository.selectByIds(addressIds);
858
        for (Address address : addresses) {
859
            addressIdAddressMap.put(address.getId(), address);
860
        }
861
        return addressIdAddressMap;
862
    }
23955 govind 863
 
31734 tejbeer 864
    private List<Integer> toAddressIds(List<ShopAddress> shopAddresses) {
35394 amit 865
        return shopAddresses.stream()
866
                .map(ShopAddress::getAddressId)
867
                .collect(Collectors.toList());
31734 tejbeer 868
    }
23955 govind 869
 
31734 tejbeer 870
    private Set<Integer> toShopIds(List<Shop> shops) {
35394 amit 871
        return shops.stream()
872
                .map(Shop::getId)
873
                .collect(Collectors.toSet());
31734 tejbeer 874
    }
23955 govind 875
 
33247 ranu 876
    private String toString(List<UserRole> userRoles) throws ProfitMandiBusinessException {
31734 tejbeer 877
        Set<Integer> roleIds = new HashSet<>();
878
        for (UserRole userRole : userRoles) {
879
            roleIds.add(userRole.getRoleId());
880
        }
881
        List<Role> roles = roleRepository.selectByIds(roleIds);
31735 amit.gupta 882
        Function<Role, String> roleToNameFunction = role -> String.valueOf(role.getName());
31734 tejbeer 883
        Set<String> userRoleStrings = roles.stream().map(roleToNameFunction).collect(Collectors.toSet());
884
        return String.join(", ", userRoleStrings);
885
    }
23955 govind 886
 
33128 amit.gupta 887
    private FofoStore createFofoStoreCodeByRetailerId(int retailerId, String districtName, String
888
            stateName, UpdateRetailerRequest updateRetailerRequest) throws ProfitMandiBusinessException {
31734 tejbeer 889
        FofoStore fofoStore = null;
890
        try {
891
            fofoStore = fofoStoreRepository.selectByRetailerId(retailerId);
892
            fofoStore.setActivationType(ActivationType.ACTIVE);
30097 tejbeer 893
 
31734 tejbeer 894
        } catch (ProfitMandiBusinessException profitMandiBusinessException) {
23955 govind 895
 
31734 tejbeer 896
        }
23955 govind 897
 
31734 tejbeer 898
        if (fofoStore != null) {
899
            fofoStore.setCounterSize(updateRetailerRequest.getCountersize());
33124 ranu 900
            fofoStore.setAstId(updateRetailerRequest.getAstId());
31734 tejbeer 901
            fofoStore.setMinimumInvestment(updateRetailerRequest.getMinInvestment());
902
            fofoStore.setWarehouseId(updateRetailerRequest.getWarehouseId());
903
            fofoStore.setCounterPotential(updateRetailerRequest.getCounterPotential());
904
            fofoStore.setFofoType(updateRetailerRequest.getFofoType());
35896 amit 905
            fofoStore.setGstNumber(updateRetailerRequest.getGstNumber());
37151 aman 906
 
907
            // The store already exists but its code may never have reached the onboarding
908
            // panel (e.g. verification approved while another dtr user held the partner's
909
            // mobile, so the approval-time linker resolved the wrong account). Re-saving the
910
            // form previously did nothing for the panel because linking only ran on NEW
911
            // store creation. Link here too; the method is a no-op if the panel already
912
            // has a code.
913
            this.linkStoreCodeToOnboardingPanel(fofoStore, updateRetailerRequest.getUserMobileNumber(), retailerId);
31734 tejbeer 914
        } else {
915
            int retailerAddressId = retailerRegisteredAddressRepository.selectAddressIdByRetailerId(retailerId);
916
            Address retailerAddress = addressRepository.selectById(retailerAddressId);
23955 govind 917
 
31734 tejbeer 918
            // StateInfo stateInfo = null;
919
            State stateInfo = null;
920
            try {
30527 tejbeer 921
 
31734 tejbeer 922
                stateInfo = stateRepository.selectByName(retailerAddress.getState());
923
                // stateInfo = Utils.getStateInfo(retailerAddress.getState());
924
            } catch (Exception e) {
925
                // TODO Auto-generated catch block
926
                e.printStackTrace();
927
                // throw new ProfitMandiBusinessException();
928
            }
929
            DistrictMaster districtMaster = districtMasterRepository.selectByNameAndStateShortName(districtName, stateInfo.getShortName());
23955 govind 930
 
31734 tejbeer 931
            fofoStore = new FofoStore();
932
            fofoStore.setId(retailerId);
933
            fofoStore.setCounterSize(updateRetailerRequest.getCountersize());
934
            fofoStore.setMinimumInvestment(updateRetailerRequest.getMinInvestment());
31730 tejbeer 935
 
31734 tejbeer 936
            fofoStore.setCounterPotential(updateRetailerRequest.getCounterPotential());
937
            fofoStore.setWarehouseId(updateRetailerRequest.getWarehouseId());
35289 amit 938
 
939
            //Check for Trial users here
32615 raveendra. 940
            int nextStoreCodeInt = fofoStoreRepository.selectLatestStore().getCodeInt() + 1;
941
 
31734 tejbeer 942
            String fofoStoreCode = StringUtils.generateFofoStoreSequence(
32615 raveendra. 943
                    districtMaster.getStateShortName() + districtMaster.getShortName(), nextStoreCodeInt);
35306 amit 944
            try {
945
                TrialForm trialForm = trialFormRepository.selectByEmailOrMobile(updateRetailerRequest.getUserMobileNumber());
946
                if (trialForm != null) {
947
                    fofoStoreCode = "T-" + fofoStoreCode;
948
                    fofoStore.setTrial(true);
949
                    fofoStore.setTrialStart(LocalDate.now());
950
                    fofoStore.setTrialEnd(LocalDate.now().plusDays(31));
35360 aman 951
                    trialForm.setStatus(ProfitMandiConstants.Status.TMP_STORE_CODE_CREATED);
35306 amit 952
                    //TODO:Amit G, Send store code notification to retailer.
953
                }
954
            } catch (ProfitMandiBusinessException e) {
35289 amit 955
            }
31734 tejbeer 956
            fofoStore.setCode(fofoStoreCode);
32615 raveendra. 957
            fofoStore.setCodeInt(nextStoreCodeInt);
31734 tejbeer 958
            fofoStore.setBagsLastCredited(LocalDateTime.now());
35203 amit 959
            if (retailerAddress.getName().contains(ProfitMandiConstants.COMPANY_NAME) || retailerAddress.getName().contains(ProfitMandiConstants.COMPANY_SHORT_NAME)) {
960
                fofoStore.setInternal(true);
961
            } else {
962
                fofoStore.setInternal(false);
963
            }
964
            fofoStore.setFofoType(FofoType.FRANCHISE);
31734 tejbeer 965
            fofoStore.setFofoType(updateRetailerRequest.getFofoType());
966
            fofoStore.setActivationType(ActivationType.ACTIVE);
35896 amit 967
            fofoStore.setGstNumber(updateRetailerRequest.getGstNumber());
36439 amit 968
            fofoStore.setOutletName(retailerAddress.getName());
31734 tejbeer 969
            fofoStoreRepository.persist(fofoStore);
28908 tejbeer 970
 
37151 aman 971
            // Link store code to onboarding panel
972
            this.linkStoreCodeToOnboardingPanel(fofoStore, retailerAddress.getPhoneNumber(), retailerId);
35971 aman 973
 
36064 aman 974
            PincodePartner pincodePartner = pincodePartnerRepository.selectPartnerByPincode(retailerAddress.getPinCode(), fofoStore.getId());
975
            if (pincodePartner == null) {
976
                PincodePartner pinPartner = new PincodePartner();
977
                pinPartner.setFofoId(fofoStore.getId());
978
                pinPartner.setPincode(retailerAddress.getPinCode());
979
                pincodePartnerRepository.perist(pinPartner);
980
            }
35418 aman 981
 
36064 aman 982
            if (fofoStore.isTrial()) {
983
                storeTimelineTatService.sendTrialStoreCreationMail(fofoStore, updateRetailerRequest);
984
                storeTimelineTatService.sendTrialActivationMail(fofoStore, updateRetailerRequest);
985
            }
35289 amit 986
        }
987
 
31734 tejbeer 988
        return fofoStore;
989
    }
23955 govind 990
 
37151 aman 991
    /**
992
     * Copies an existing fofo_store code onto the partner_onboarding_panel row for the
993
     * given mobile number, provided verification is approved and the panel does not
994
     * already hold a code. Called for BOTH new and existing stores: the approval-time
995
     * linker in PartnerOnBoardingPanelController can miss (e.g. kyc=0, or a legacy dtr
996
     * user squatting on the partner's mobile made selectByMobileNumber resolve the
997
     * wrong account), and before this method existed a form re-save silently skipped
998
     * linking whenever the store already existed. Best-effort: never fails the save.
999
     */
1000
    private void linkStoreCodeToOnboardingPanel(FofoStore fofoStore, String phoneNumber, int retailerId) {
1001
        if (fofoStore == null || fofoStore.getCode() == null || fofoStore.getCode().isEmpty()
1002
                || phoneNumber == null || phoneNumber.isEmpty()) {
1003
            return;
1004
        }
1005
        try {
1006
            PartnerOnBoardingPanel pobp = partnerOnBoardingPanelRepository.selectByPhoneNumber(
1007
                    Long.parseLong(phoneNumber));
1008
            if (pobp == null) {
1009
                return;
1010
            }
1011
            // Never overwrite: multi-store / GST-change onboardings keep their own codes.
1012
            if (pobp.getCode() != null && !pobp.getCode().isEmpty()) {
1013
                return;
1014
            }
1015
            PartnerVerificationpanel pvp = partnerOnboardingVerificationRepository
1016
                    .selectByOnboardingId(pobp.getId());
1017
            if (pvp != null && PartnerVerificationApprovalStatus.YES.equals(pvp.getApproval())) {
1018
                pobp.setCode(fofoStore.getCode());
1019
                storeTimelineTatService.onCodeCreated(pobp.getId());
1020
                PartnerVerificationCheckboxes cb = partnerOnboardingVerificationRepository
1021
                        .selectVerifiCheckboxByOnboardingId(pobp.getId());
1022
                if (cb == null) {
1023
                    cb = new PartnerVerificationCheckboxes();
1024
                    cb.setOnboardingId(pobp.getId());
1025
                    partnerOnboardingVerificationRepository.persist(cb);
1026
                }
1027
                LOGGER.info("Linked store code {} to onboardingId {} for retailerId {}",
1028
                        fofoStore.getCode(), pobp.getId(), retailerId);
1029
            }
1030
        } catch (Exception e) {
1031
            LOGGER.error("Error linking store code to onboarding for retailerId: {}", retailerId, e);
1032
        }
1033
    }
1034
 
31734 tejbeer 1035
    @Override
33128 amit.gupta 1036
    public FofoStore createFofoStoreCodeByUserId(int userId, String districtName, String
1037
            stateName, UpdateRetailerRequest updateRetailerRequest) throws ProfitMandiBusinessException {
31734 tejbeer 1038
        User user = userRepository.selectById(userId);
1039
        // = userAccountRepository.selectRetailerIdByUserId(user.getId());
1040
        UserAccount userAccounts = userAccountRepository.selectSaholicByUserId(user.getId());
1041
        Retailer retailer = retailerRepository.selectById(userAccounts.getAccountKey());
1042
        Role roleFofo = roleRepository.selectByName(RoleType.FOFO.toString());
1043
        try {
1044
            userRoleRepository.selectByUserIdAndRoleId(user.getId(), roleFofo.getId());
1045
        } catch (ProfitMandiBusinessException profitMandiBusinessException) {
1046
            throw new ProfitMandiBusinessException(ProfitMandiConstants.USER_ID, user.getId(), "USR_1013");
1047
        }
1048
        return this.createFofoStoreCodeByRetailerId(retailer.getId(), districtName, stateName, updateRetailerRequest);
23955 govind 1049
 
31734 tejbeer 1050
    }
23955 govind 1051
 
31734 tejbeer 1052
    @Override
1053
    public List<DistrictMaster> getAllDistrictMaster(String stateName) {
1054
        // StateInfo stateInfo = null;
1055
        State stateInfo = null;
1056
        try {
1057
            // stateInfo = Utils.getStateInfo(stateName);
30525 tejbeer 1058
 
31734 tejbeer 1059
            stateInfo = stateRepository.selectByName(stateName);
1060
        } catch (Exception e) {
1061
            e.printStackTrace();
1062
            // throw new ProfitMandiBusinessException();
1063
        }
1064
        return districtMasterRepository.selectByStateShortName(stateInfo.getShortName());
1065
    }
22980 ashik.ali 1066
 
31734 tejbeer 1067
    @Override
34149 tejus.loha 1068
    @Cacheable(value = "getFofoRetailer", cacheManager = "thirtyMinsTimeOutCacheManager")
33247 ranu 1069
    public Map<Integer, CustomRetailer> getFofoRetailers(List<Integer> fofoIds) throws ProfitMandiBusinessException {
35394 amit 1070
        if (fofoIds == null || fofoIds.isEmpty()) {
1071
            return new HashMap<>();
1072
        }
1073
 
31734 tejbeer 1074
        List<com.spice.profitmandi.dao.entity.user.User> saholicUsers = userUserRepository.selectByIds(fofoIds);
35440 amit 1075
 
1076
        // Check for saholicUsers without corresponding dtrUser
1077
        List<String> saholicEmails = saholicUsers.stream()
1078
                .map(com.spice.profitmandi.dao.entity.user.User::getEmailId)
1079
                .filter(email -> email != null)
1080
                .collect(Collectors.toList());
1081
        Set<String> dtrUserEmails = userRepository.selectAllByEmailIds(saholicEmails).stream()
1082
                .map(User::getEmailId)
1083
                .collect(Collectors.toSet());
1084
        for (com.spice.profitmandi.dao.entity.user.User saholicUser : saholicUsers) {
1085
            if (saholicUser.getEmailId() != null && !dtrUserEmails.contains(saholicUser.getEmailId())) {
1086
                LOGGER.warn("dtrUser not found for saholicUser - id: {}, email: {}", saholicUser.getId(), saholicUser.getEmailId());
1087
            }
1088
        }
1089
 
35394 amit 1090
        Map<Integer, com.spice.profitmandi.dao.entity.user.User> userAddressMap = saholicUsers.stream()
1091
                .filter(x -> x.getAddressId() != null)
1092
                .collect(Collectors.toMap(com.spice.profitmandi.dao.entity.user.User::getAddressId, x -> x));
31734 tejbeer 1093
        List<Address> addresses = addressRepository.selectByIds(new ArrayList<>(userAddressMap.keySet()));
35394 amit 1094
 
1095
        // Batch fetch all FofoStores to avoid N+1 queries
1096
        Set<Integer> retailerIds = addresses.stream().map(Address::getRetaierId).collect(Collectors.toSet());
1097
        Map<Integer, FofoStore> fofoStoreMap = fofoStoreRepository.selectByRetailerIds(new ArrayList<>(retailerIds))
1098
                .stream().collect(Collectors.toMap(FofoStore::getId, fs -> fs));
1099
 
31734 tejbeer 1100
        Map<Integer, CustomRetailer> customRetailersMap = new HashMap<>();
1101
        for (Address address : addresses) {
1102
            com.spice.profitmandi.dao.entity.user.User user = userAddressMap.get(address.getId());
35394 amit 1103
            FofoStore fs = fofoStoreMap.get(address.getRetaierId());
1104
            if (fs == null) {
31734 tejbeer 1105
                continue;
1106
            }
35394 amit 1107
 
35896 amit 1108
            CustomRetailer customRetailer = buildCustomRetailer(user, address, fs);
31734 tejbeer 1109
            customRetailersMap.put(customRetailer.getPartnerId(), customRetailer);
1110
        }
1111
        return customRetailersMap;
1112
    }
25295 amit.gupta 1113
 
35394 amit 1114
    /**
1115
     * Helper method to build CustomRetailer from fetched entities
1116
     */
1117
    private CustomRetailer buildCustomRetailer(com.spice.profitmandi.dao.entity.user.User user, Address address,
35896 amit 1118
                                               FofoStore fs) {
35394 amit 1119
        CustomRetailer customRetailer = new CustomRetailer();
1120
        customRetailer.setEmail(user.getEmailId());
1121
        customRetailer.setBusinessName(address.getName());
1122
        customRetailer.setMobileNumber(address.getPhoneNumber());
1123
        customRetailer.setCode(fs.getCode());
1124
        customRetailer.setAstId(fs.getAstId());
1125
        customRetailer.setActivationType(fs.getActivationType());
1126
        customRetailer.setCounterSize(fs.getCounterSize());
1127
        customRetailer.setCounterPotential(fs.getCounterPotential());
1128
        customRetailer.setWarehouseId(fs.getWarehouseId());
1129
        customRetailer.setPartnerId(fs.getId());
1130
        customRetailer.setFofoType(fs.getFofoType());
1131
        customRetailer.setCartId(user.getActiveCartId());
1132
 
35896 amit 1133
        customRetailer.setGstNumber(fs.getGstNumber());
35394 amit 1134
 
1135
        CustomAddress customAddress = buildCustomAddress(address);
1136
        customRetailer.setAddress(customAddress);
1137
        customRetailer.setDisplayName(customRetailer.getBusinessName() + "-" + customRetailer.getCode() + "- " + customAddress.getCity());
1138
        return customRetailer;
1139
    }
1140
 
1141
    /**
1142
     * Helper method to build CustomAddress from Address entity
1143
     */
1144
    private CustomAddress buildCustomAddress(Address address) {
1145
        CustomAddress customAddress = new CustomAddress();
1146
        customAddress.setCity(address.getCity());
1147
        customAddress.setState(address.getState());
1148
        customAddress.setLine1(address.getLine1());
1149
        customAddress.setLine2(address.getLine2());
1150
        customAddress.setPinCode(address.getPinCode());
1151
        customAddress.setName(address.getName());
1152
        customAddress.setPhoneNumber(address.getPhoneNumber());
1153
        return customAddress;
1154
    }
1155
 
31734 tejbeer 1156
    @Override
1157
    @Cacheable(value = "getFofoRetailer", cacheManager = "thirtyMinsTimeOutCacheManager")
1158
    public CustomRetailer getFofoRetailer(int fofoId) throws ProfitMandiBusinessException {
1159
        com.spice.profitmandi.dao.entity.user.User saholicUser = userUserRepository.selectById(fofoId);
35440 amit 1160
        User dtrUser = null;
1161
        try {
1162
            dtrUser = userRepository.selectByEmailId(saholicUser.getEmailId());
1163
        } catch (ProfitMandiBusinessException e) {
1164
            LOGGER.info("User not found for emailId: {} and id is : {}", saholicUser.getEmailId(), saholicUser.getId());
1165
        }
31734 tejbeer 1166
        FofoStore store = fofoStoreRepository.selectByRetailerId(fofoId);
35394 amit 1167
        Address address = addressRepository.selectById(saholicUser.getAddressId());
1168
 
31734 tejbeer 1169
        CustomRetailer customRetailer = new CustomRetailer();
1170
        customRetailer.setEmail(saholicUser.getEmailId());
1171
        customRetailer.setBusinessName(address.getName());
1172
        customRetailer.setMobileNumber(address.getPhoneNumber());
31862 tejbeer 1173
        customRetailer.setFirstName(dtrUser.getFirstName());
1174
        customRetailer.setLastName(dtrUser.getLastName());
35394 amit 1175
        customRetailer.setCartId(saholicUser.getActiveCartId());
1176
        customRetailer.setPartnerId(address.getRetaierId());
1177
        customRetailer.setCode(store.getCode());
1178
        customRetailer.setAstId(store.getAstId());
1179
        customRetailer.setActivationType(store.getActivationType());
1180
        customRetailer.setWarehouseId(store.getWarehouseId());
1181
 
35896 amit 1182
        customRetailer.setGstNumber(store.getGstNumber());
35394 amit 1183
 
1184
        // Reuse helper method for CustomAddress
1185
        CustomAddress customAddress = buildCustomAddress(address);
1186
        customRetailer.setAddress(customAddress);
31734 tejbeer 1187
        customRetailer.setDisplayName(address.getName() + " - " + address.getCity());
35394 amit 1188
 
31734 tejbeer 1189
        return customRetailer;
1190
    }
26125 amit.gupta 1191
 
31734 tejbeer 1192
    @Override
33247 ranu 1193
    public Map<Integer, CustomRetailer> getFofoRetailerUserId(List<Integer> fofoIds) throws ProfitMandiBusinessException {
35394 amit 1194
        if (fofoIds == null || fofoIds.isEmpty()) {
1195
            return new HashMap<>();
1196
        }
1197
 
31734 tejbeer 1198
        List<com.spice.profitmandi.dao.entity.user.User> saholicUsers = userUserRepository.selectByIds(fofoIds);
35394 amit 1199
        Map<Integer, com.spice.profitmandi.dao.entity.user.User> userAddressMap = saholicUsers.stream()
1200
                .filter(x -> x.getAddressId() != null)
1201
                .collect(Collectors.toMap(com.spice.profitmandi.dao.entity.user.User::getAddressId, x -> x));
31734 tejbeer 1202
        List<Address> addresses = addressRepository.selectByIds(new ArrayList<>(userAddressMap.keySet()));
35394 amit 1203
 
1204
        // Batch fetch all retailerIds to userIds mapping to avoid N+1
1205
        Set<Integer> retailerIds = addresses.stream().map(Address::getRetaierId).collect(Collectors.toSet());
1206
        Map<Integer, Integer> retailerIdToUserIdMap = getUserIdRetailerIdMapReverse(retailerIds);
1207
 
35896 amit 1208
        // Batch fetch FofoStores for GST numbers
1209
        Map<Integer, FofoStore> fofoStoreMap = fofoStoreRepository.selectByRetailerIds(new ArrayList<>(retailerIds))
1210
                .stream().collect(Collectors.toMap(FofoStore::getId, fs -> fs));
35394 amit 1211
 
31734 tejbeer 1212
        Map<Integer, CustomRetailer> customRetailersMap = new HashMap<>();
1213
        for (Address address : addresses) {
1214
            com.spice.profitmandi.dao.entity.user.User user = userAddressMap.get(address.getId());
35394 amit 1215
            Integer userId = retailerIdToUserIdMap.get(user.getId());
1216
            if (userId == null) {
1217
                continue;
1218
            }
1219
 
31734 tejbeer 1220
            CustomRetailer customRetailer = new CustomRetailer();
1221
            customRetailer.setEmail(user.getEmailId());
1222
            customRetailer.setBusinessName(address.getName());
1223
            customRetailer.setMobileNumber(address.getPhoneNumber());
35394 amit 1224
            customRetailer.setCartId(user.getActiveCartId());
1225
            customRetailer.setPartnerId(address.getRetaierId());
1226
 
35896 amit 1227
            FofoStore fs = fofoStoreMap.get(address.getRetaierId());
1228
            customRetailer.setGstNumber(fs != null ? fs.getGstNumber() : null);
35394 amit 1229
 
1230
            CustomAddress customAddress = buildCustomAddress(address);
1231
            customRetailer.setAddress(customAddress);
1232
            customRetailer.setDisplayName(customRetailer.getBusinessName() + "-" + customAddress.getCity());
31734 tejbeer 1233
            customRetailersMap.put(userId, customRetailer);
1234
        }
1235
        return customRetailersMap;
1236
    }
25295 amit.gupta 1237
 
35394 amit 1238
    /**
1239
     * Helper method to get retailerId to userId mapping
1240
     */
1241
    private Map<Integer, Integer> getUserIdRetailerIdMapReverse(Set<Integer> retailerIds) {
1242
        List<UserAccount> userAccounts = userAccountRepository.selectAllSaholicByRetailerIds(retailerIds);
1243
        return userAccounts.stream().collect(Collectors.toMap(UserAccount::getAccountKey, UserAccount::getUserId));
1244
    }
1245
 
31734 tejbeer 1246
    @Override
33247 ranu 1247
    public Map<Integer, String> getAllFofoRetailerIdEmailIdMap() throws ProfitMandiBusinessException {
31734 tejbeer 1248
        Role roleFofo = null;
1249
        try {
1250
            roleFofo = roleRepository.selectByName(RoleType.FOFO.toString());
1251
        } catch (ProfitMandiBusinessException e) {
1252
            // TODO Auto-generated catch block
1253
            e.printStackTrace();
1254
        }
1255
        Role roleRetailer = null;
1256
        try {
1257
            roleRetailer = roleRepository.selectByName(RoleType.RETAILER.toString());
1258
        } catch (ProfitMandiBusinessException e) {
1259
            // TODO Auto-generated catch block
1260
            e.printStackTrace();
1261
        }
1262
        Set<Integer> roleIds = new HashSet<>();
1263
        roleIds.add(roleFofo.getId());
1264
        roleIds.add(roleRetailer.getId());
1265
        List<Integer> userIds = userRoleRepository.selectUserIdsByRoleIds(roleIds);
1266
        List<User> users = userRepository.selectAllByIds(new HashSet<>(userIds));
1267
        Map<Integer, Integer> userIdRetailerIdMap = this.getUserIdRetailerIdMap(userIds);
1268
        Map<Integer, String> retailerIdEmailIdMap = new HashMap<>();
1269
        for (User user : users) {
1270
            retailerIdEmailIdMap.put(userIdRetailerIdMap.get(user.getId()), user.getEmailId());
1271
        }
1272
        return retailerIdEmailIdMap;
1273
    }
23955 govind 1274
 
31734 tejbeer 1275
    private Map<Integer, Integer> getUserIdRetailerIdMap(List<Integer> userIds) {
1276
        List<UserAccount> userAccounts = userAccountRepository.selectAllSaholicByUserIds(new HashSet<>(userIds));
1277
        Map<Integer, Integer> userIdRetailerIdMap = new HashMap<>();
1278
        for (UserAccount userAccount : userAccounts) {
1279
            userIdRetailerIdMap.put(userAccount.getUserId(), userAccount.getAccountKey());
1280
        }
1281
        return userIdRetailerIdMap;
1282
    }
25295 amit.gupta 1283
 
33247 ranu 1284
    private Map<Integer, String> getUserIdEmailIdMap(Set<Integer> userIds) throws ProfitMandiBusinessException {
31734 tejbeer 1285
        List<User> users = userRepository.selectAllByIds(userIds);
1286
        Map<Integer, String> userIdEmailIdMap = new HashMap<>();
1287
        for (User user : users) {
1288
            userIdEmailIdMap.put(user.getId(), user.getEmailId());
1289
        }
1290
        return userIdEmailIdMap;
1291
    }
23509 amit.gupta 1292
 
31734 tejbeer 1293
    @Override
33247 ranu 1294
    public Map<Integer, String> getAllFofoRetailerIdEmailIdMap(Set<Integer> retailerIds) throws ProfitMandiBusinessException {
31734 tejbeer 1295
        List<UserAccount> userAccounts = userAccountRepository.selectAllSaholicByRetailerIds(retailerIds);
1296
        Set<Integer> userIds = new HashSet<>();
1297
        for (UserAccount userAccount : userAccounts) {
1298
            userIds.add(userAccount.getUserId());
1299
        }
1300
        Map<Integer, String> retailerIdEmailIdMap = new HashMap<>();
1301
        Map<Integer, String> userIdEmailIdMap = this.getUserIdEmailIdMap(userIds);
1302
        for (UserAccount userAccount : userAccounts) {
1303
            retailerIdEmailIdMap.put(userAccount.getAccountKey(), userIdEmailIdMap.get(userAccount.getUserId()));
1304
        }
1305
        return retailerIdEmailIdMap;
1306
    }
25295 amit.gupta 1307
 
31734 tejbeer 1308
    @Override
33247 ranu 1309
    public Map<Integer, String> getAllFofoRetailerIdNameMap(List<Integer> storeIds) throws ProfitMandiBusinessException {
31734 tejbeer 1310
        Map<Integer, CustomRetailer> retailersMap = this.getFofoRetailers(storeIds);
1311
        Map<Integer, String> retailerIdNameMap = new HashMap<>();
1312
        for (Map.Entry<Integer, CustomRetailer> entry : retailersMap.entrySet()) {
1313
            retailerIdNameMap.put(entry.getKey(), entry.getValue().getBusinessName() + "-" + entry.getValue().getAddress().getCity());
1314
        }
1315
        return retailerIdNameMap;
1316
    }
24168 amit.gupta 1317
 
31734 tejbeer 1318
    @Override
1319
    @Cacheable(value = "FofoRetailerIdNameMap", cacheManager = "thirtyMinsTimeOutCacheManager")
33247 ranu 1320
    public Map<Integer, String> getAllFofoRetailerIdNameMap() throws ProfitMandiBusinessException {
31734 tejbeer 1321
        List<FofoStore> stores = fofoStoreRepository.selectAll();
1322
        List<Integer> storeIds = stores.stream().map(x -> x.getId()).collect(Collectors.toList());
1323
        return this.getAllFofoRetailerIdNameMap(storeIds);
1324
    }
24349 amit.gupta 1325
 
31734 tejbeer 1326
    @Override
33247 ranu 1327
    public List<MapWrapper<Integer, String>> getAllFofoRetailerIdNameList() throws ProfitMandiBusinessException {
31734 tejbeer 1328
        List<MapWrapper<Integer, String>> mapWrappers = new ArrayList<>();
1329
        // TODO Auto-generated method stub
1330
        Map<Integer, String> fofoIdNameMap = this.getAllFofoRetailerIdNameMap();
1331
        fofoIdNameMap.forEach((fofoId, name) -> {
1332
            MapWrapper<Integer, String> idWrapper = new MapWrapper<>();
1333
            idWrapper.setKey(fofoId);
1334
            idWrapper.setValue(name);
1335
            mapWrappers.add(idWrapper);
1336
        });
1337
        return mapWrappers;
1338
    }
24349 amit.gupta 1339
 
31734 tejbeer 1340
    @Override
1341
    @Cacheable(value = "retailerNames", cacheManager = "thirtyMinsTimeOutCacheManager")
33247 ranu 1342
    public Map<Integer, CustomRetailer> getFofoRetailers(boolean activeOnly) throws ProfitMandiBusinessException {
35394 amit 1343
        Stream<FofoStore> storeStream = fofoStoreRepository.selectAll().stream()
1344
                .filter(fs -> fs.getFofoType().equals(FofoType.FRANCHISE));
31734 tejbeer 1345
        if (activeOnly) {
35394 amit 1346
            storeStream = storeStream.filter(FofoStore::isActive);
31734 tejbeer 1347
        }
35394 amit 1348
        List<Integer> storeIds = storeStream.map(FofoStore::getId).collect(Collectors.toList());
31734 tejbeer 1349
        return this.getFofoRetailers(storeIds);
1350
    }
25295 amit.gupta 1351
 
31734 tejbeer 1352
    @Override
33367 ranu 1353
    @Cacheable(value = "retailerNames", cacheManager = "thirtyMinsTimeOutCacheManager")
1354
    public Map<Integer, CustomRetailer> getFofoRetailers(boolean activeOnly, String pinCode) throws ProfitMandiBusinessException {
1355
        List<PincodePartner> pincodePartners = pincodePartnerRepository.selectPartnersByPincode(pinCode);
1356
        List<Integer> storeIds = new ArrayList<>();
35394 amit 1357
        if (!pincodePartners.isEmpty()) {
1358
            List<Integer> fofoIds = pincodePartners.stream().map(PincodePartner::getFofoId).collect(Collectors.toList());
33367 ranu 1359
            List<FofoStore> fofoStores = fofoStoreRepository.selectActivePartnersByRetailerIds(fofoIds);
35394 amit 1360
            storeIds = fofoStores.stream().map(FofoStore::getId).collect(Collectors.toList());
33367 ranu 1361
        }
1362
        return this.getFofoRetailers(storeIds);
1363
    }
1364
 
1365
    @Override
31734 tejbeer 1366
    @Cacheable(value = "allFofoRetailers", cacheManager = "thirtyMinsTimeOutCacheManager")
33247 ranu 1367
    public Map<Integer, CustomRetailer> getAllFofoRetailers() throws ProfitMandiBusinessException {
35394 amit 1368
        List<Integer> storeIds = fofoStoreRepository.selectAll().stream()
1369
                .map(FofoStore::getId)
1370
                .collect(Collectors.toList());
31734 tejbeer 1371
        return this.getFofoRetailers(storeIds);
1372
    }
27861 tejbeer 1373
 
31734 tejbeer 1374
    @Override
34619 ranu 1375
    @Cacheable(value = "allFofoRetailersInternalFalse", cacheManager = "thirtyMinsTimeOutCacheManager")
1376
    public Map<Integer, CustomRetailer> getAllFofoRetailersInternalFalse() throws ProfitMandiBusinessException {
35394 amit 1377
        List<Integer> storeIds = fofoStoreRepository.selectAll().stream()
1378
                .filter(fs -> fs.getFofoType().equals(FofoType.FRANCHISE))
1379
                .map(FofoStore::getId)
1380
                .collect(Collectors.toList());
34619 ranu 1381
        return this.getFofoRetailers(storeIds);
1382
    }
1383
 
1384
    @Override
33128 amit.gupta 1385
    public LoginRequestResponseModel registerWebUser(LoginRequestResponseModel loginRequestModel) throws
1386
            ProfitMandiBusinessException {
26522 amit.gupta 1387
 
31734 tejbeer 1388
        com.spice.profitmandi.dao.entity.user.User saholicUser = this.createSaholicUser(loginRequestModel);
1389
        loginRequestModel.setUserId(saholicUser.getId());
26522 amit.gupta 1390
 
31734 tejbeer 1391
        this.createRetailerAddress(loginRequestModel);
26522 amit.gupta 1392
 
31734 tejbeer 1393
        this.updateSaholicUser(saholicUser.getId(), loginRequestModel.getBusinessAddress().getId());
26522 amit.gupta 1394
 
31734 tejbeer 1395
        return loginRequestModel;
26522 amit.gupta 1396
 
31734 tejbeer 1397
    }
26522 amit.gupta 1398
 
33128 amit.gupta 1399
    private void createRetailerAddress(LoginRequestResponseModel loginRequestResponseModel) throws
1400
            ProfitMandiBusinessException {
31734 tejbeer 1401
        Address businessAddress = loginRequestResponseModel.getBusinessAddress();
1402
        businessAddress.setRetaierId(loginRequestResponseModel.getUserId());
1403
        addressRepository.persist(businessAddress);
1404
    }
26536 amit.gupta 1405
 
31734 tejbeer 1406
    private String getHash256(String originalString) {
1407
        String hashString = Hashing.sha256().hashString(originalString, StandardCharsets.UTF_8).toString();
1408
        LOGGER.info("Hash String {}", hashString);
1409
        return hashString;
1410
    }
26533 amit.gupta 1411
 
31734 tejbeer 1412
    @Override
1413
    @Cacheable(value = "fofoIdUrl", cacheManager = "thirtyMinsTimeOutCacheManager")
1414
    public Map<Integer, String> getAllFofoRetailerIdUrlMap() {
1415
        Map<Integer, String> fofoRetailerUrlMap = new HashMap<>();
35394 amit 1416
        List<FofoStore> stores = fofoStoreRepository.selectAll().stream()
1417
                .filter(FofoStore::isActive)
1418
                .collect(Collectors.toList());
1419
 
1420
        // Batch fetch all district masters to avoid N+1 queries
1421
        List<DistrictMaster> allDistrictMasters = districtMasterRepository.selectAll();
1422
        Map<String, DistrictMaster> districtMasterMap = allDistrictMasters.stream()
1423
                .collect(Collectors.toMap(
1424
                        dm -> dm.getStateShortName() + "_" + dm.getShortName(),
1425
                        dm -> dm,
1426
                        (existing, replacement) -> existing));
1427
 
1428
        // Get fallback district master
1429
        DistrictMaster fallbackDistrict = districtMasterMap.get("HR_FB");
1430
 
31734 tejbeer 1431
        for (FofoStore store : stores) {
35394 amit 1432
            String codeWithoutDigits = store.getCode().replaceAll("\\d+", "");
1433
            if (codeWithoutDigits.length() < 3) {
1434
                LOGGER.warn("Invalid store code format: {}", store.getCode());
1435
                continue;
1436
            }
1437
            String stateShortName = codeWithoutDigits.substring(0, 2);
1438
            String districtShortName = codeWithoutDigits.substring(2);
1439
 
1440
            // Use pre-fetched map instead of N+1 query
1441
            String key = stateShortName + "_" + districtShortName;
1442
            DistrictMaster districtMaster = districtMasterMap.getOrDefault(key, fallbackDistrict);
1443
 
31734 tejbeer 1444
            if (districtMaster == null) {
35394 amit 1445
                LOGGER.warn("No district master found for key: {} and no fallback available", key);
1446
                continue;
31734 tejbeer 1447
            }
35394 amit 1448
 
1449
            String urlString = districtMaster.getStateShortName() + "/" +
1450
                    Utils.getHyphenatedString(districtMaster.getName()) + "/" + store.getCode();
31734 tejbeer 1451
            fofoRetailerUrlMap.put(store.getId(), urlString.toLowerCase());
1452
        }
1453
        return fofoRetailerUrlMap;
1454
    }
26533 amit.gupta 1455
 
31734 tejbeer 1456
    @Override
1457
    @Cacheable(value = "storeCodeRetailerMap", cacheManager = "thirtyMinsTimeOutCacheManager")
1458
    public Map<String, Integer> getStoreCodeRetailerMap() {
1459
        Map<Integer, String> map = this.getAllFofoRetailerIdUrlMap();
1460
        Map<String, Integer> returnMap = map.entrySet().stream().collect(Collectors.toMap(x -> {
1461
            String[] splitString = x.getValue().split("/");
1462
            return splitString[splitString.length - 1];
1463
        }, x -> x.getKey()));
1464
        LOGGER.info("returnMap {}", returnMap);
1465
        return returnMap;
1466
    }
27877 amit.gupta 1467
 
1468
 
31734 tejbeer 1469
    @Override
32668 raveendra. 1470
    public User getEmail() {
1471
        return null;
1472
    }
1473
 
1474
    @Override
1475
    public void update(com.spice.profitmandi.dao.entity.user.User user) {
1476
    }
1477
 
1478
    @Override
1479
    public void updateRetailerEmail(int fofoId, String newEmail) throws ProfitMandiBusinessException {
1480
        User dtrUser = null;
1481
        com.spice.profitmandi.dao.entity.user.User user = null;
1482
 
1483
        try {
1484
            dtrUser = userRepository.selectByEmailId(newEmail);
1485
        } catch (Exception e) {
1486
        }
1487
 
1488
        try {
1489
            user = userUserRepository.selectByEmailId(newEmail);
1490
        } catch (Exception e) {
1491
        }
1492
 
1493
        if (user != null || dtrUser != null) {
1494
            throw new ProfitMandiBusinessException("Email", newEmail, "Email already exist");
1495
        }
1496
        com.spice.profitmandi.dao.entity.user.User fofoUser = userUserRepository.selectById(fofoId);
1497
        String oldEmail = fofoUser.getEmailId();
1498
        LOGGER.info("old email {}", oldEmail);
1499
        User thisDtrUser = userRepository.selectByEmailId(oldEmail);
1500
 
1501
        fofoUser.setEmailId(newEmail);
1502
        thisDtrUser.setEmailId(newEmail);
1503
    }
1504
 
1505
 
32953 amit.gupta 1506
    //    @Override
32737 amit.gupta 1507
    @Cacheable(value = "getContactsByFofoId", cacheManager = "oneDayCacheManager")
33128 amit.gupta 1508
    public List<RetailerContact> getContactsByFofoId(int fofoId, boolean activeOnly) throws
1509
            ProfitMandiBusinessException {
32737 amit.gupta 1510
        List<RetailerContact> retailerContacts = retailerContactRepository.selectAllByRetailerId(fofoId, activeOnly);
1511
        com.spice.profitmandi.dao.entity.user.User user = userUserRepository.selectById(fofoId);
1512
        RetailerContact retailerContact = new RetailerContact();
1513
        retailerContact.setMobile(user.getMobileNumber());
1514
        retailerContact.setName(user.getName());
1515
        retailerContact.setActive(true);
1516
        retailerContact.setFofoId(fofoId);
1517
        retailerContacts.add(retailerContact);
1518
        return retailerContacts;
1519
    }
1520
 
1521
 
1522
    @Override
33128 amit.gupta 1523
    public Map<Integer, CustomRetailer> getFofoRetailersPaginated(boolean activeOnly, int offset,
33247 ranu 1524
                                                                  int limit, FofoType fofoType) throws ProfitMandiBusinessException {
30097 tejbeer 1525
 
31734 tejbeer 1526
        Stream<FofoStore> storeStream = fofoStoreRepository.selectByStatusFofoType(activeOnly, fofoType, offset, limit).stream();
30219 tejbeer 1527
 
31734 tejbeer 1528
        List<Integer> storeIds = storeStream.map(x -> x.getId()).collect(Collectors.toList());
1529
        return this.getFofoRetailers(storeIds);
1530
    }
30219 tejbeer 1531
 
34813 aman 1532
    @Override
1533
    public Map<String, Object> computeIncomeMap(int fofoId, int yearMonth) {
1534
        LocalDateTime startOfMonth = LocalDate.now().minusMonths(yearMonth).withDayOfMonth(1).atStartOfDay();
1535
        LocalDateTime endOfMonth = startOfMonth.plusMonths(1);
1536
        YearMonth monthYear = YearMonth.now();
1537
 
1538
 
1539
        // 3) Fetch brand-wise data (same as original)
1540
        List<LastMonthCreditedIncomeModel> lastMonthPendingIncomeModels = schemeInOutRepository
1541
                .selectLastMonthPendingIncomeByFofoId(fofoId, startOfMonth, endOfMonth);
1542
 
1543
        List<LastMonthCreditedIncomeModel> lastMonthPurchaseInMargins = schemeInOutRepository
1544
                .selectLastMonthPurchaseInMarginByFofoId(fofoId, startOfMonth, endOfMonth);
1545
 
1546
        List<LastMonthCreditedIncomeModel> lastMonthFrontEndIncomes = schemeInOutRepository
1547
                .selectFrontIncomeByBrand(fofoId, startOfMonth, endOfMonth);
1548
 
1549
        List<LastMonthCreditedIncomeModel> lastMonthSaleMargins = schemeInOutRepository
1550
                .selectLastMonthCreditedIncomeByFofoId(fofoId, startOfMonth, endOfMonth);
1551
 
1552
        List<OfferPayoutImeiIncomeModel> offerPayoutImeiIncomeModels = offerPayoutRepository
1553
                .getTotalPayoutsByPartnerPeriod(
1554
                        YearMonth.of(startOfMonth.getYear(), startOfMonth.getMonth()),
1555
                        fofoId, null, null);
1556
 
1557
        // 4) Convert to maps for brand-wise access
1558
        Map<String, LastMonthCreditedIncomeModel> lastMonthPendingIncomeMap =
1559
                lastMonthPendingIncomeModels.stream()
1560
                        .collect(Collectors.toMap(x -> x.getBrand(), x -> x));
1561
 
1562
        Map<String, LastMonthCreditedIncomeModel> lastMonthPurchaseInMarginMap =
1563
                lastMonthPurchaseInMargins.stream()
1564
                        .collect(Collectors.toMap(x -> x.getBrand(), x -> x));
1565
 
1566
        Map<String, LastMonthCreditedIncomeModel> lastMonthFrontEndIncomeMap =
1567
                lastMonthFrontEndIncomes.stream()
1568
                        .collect(Collectors.toMap(x -> x.getBrand(), x -> x));
1569
 
1570
        Map<String, LastMonthCreditedIncomeModel> lastMonthSaleMarginMap =
1571
                lastMonthSaleMargins.stream()
1572
                        .collect(Collectors.toMap(x -> x.getBrand(), x -> x));
1573
 
1574
        Map<String, Double> additionalPurchasePayout = offerPayoutImeiIncomeModels.stream()
1575
                .collect(Collectors.groupingBy(OfferPayoutImeiIncomeModel::getBrand,
1576
                        Collectors.summingDouble(OfferPayoutImeiIncomeModel::getPurchasePayout)));
1577
 
1578
        Map<String, Double> additionSalePayout = offerPayoutImeiIncomeModels.stream()
1579
                .collect(Collectors.groupingBy(OfferPayoutImeiIncomeModel::getBrand,
1580
                        Collectors.summingDouble(OfferPayoutImeiIncomeModel::getSalePayout)));
1581
 
1582
        // 5) Get all unique brands
1583
        Set<String> brandSet = new HashSet<>();
1584
        brandSet.addAll(lastMonthPurchaseInMarginMap.keySet());
1585
        brandSet.addAll(lastMonthSaleMarginMap.keySet());
1586
        brandSet.addAll(lastMonthPendingIncomeMap.keySet());
1587
        brandSet.addAll(additionalPurchasePayout.keySet());
1588
        brandSet.addAll(additionSalePayout.keySet());
1589
        brandSet.addAll(lastMonthFrontEndIncomeMap.keySet());
1590
 
1591
        // 6) Calculate total amount per brand (same logic as original)
1592
        Map<String, Float> totalAmountMap = new HashMap<>();
1593
        brandSet.forEach(brand -> {
1594
            float total =
1595
                    (lastMonthSaleMarginMap.get(brand) == null ? 0 : lastMonthSaleMarginMap.get(brand).getAmount()) +
1596
                            (lastMonthPurchaseInMarginMap.get(brand) == null ? 0 : lastMonthPurchaseInMarginMap.get(brand).getAmount()) +
1597
                            (lastMonthPendingIncomeMap.get(brand) == null ? 0 : lastMonthPendingIncomeMap.get(brand).getAmount()) +
1598
                            (additionalPurchasePayout.get(brand) == null ? 0 : additionalPurchasePayout.get(brand).floatValue()) +
1599
                            (additionSalePayout.get(brand) == null ? 0 : additionSalePayout.get(brand).floatValue()) +
1600
                            (lastMonthFrontEndIncomeMap.get(brand) == null ? 0 : lastMonthFrontEndIncomeMap.get(brand).getAmount());
1601
            totalAmountMap.put(brand, total);
1602
        });
1603
 
1604
        // 7) Calculate aggregated totals
1605
        float totalIncome = totalAmountMap.values().stream()
1606
                .reduce(0f, Float::sum);
1607
 
1608
        float pendingIncome = lastMonthPendingIncomeMap.values().stream()
1609
                .map(LastMonthCreditedIncomeModel::getAmount)
1610
                .reduce(0f, Float::sum);
1611
 
1612
        float creditedIncome = totalIncome - pendingIncome;
1613
 
1614
        // 8) Build month labels
1615
        Map<Integer, String> monthValueMap = new HashMap<>();
1616
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("MMM''uu");
1617
        for (int i = 0; i <= 5; i++) {
1618
            LocalDateTime m = LocalDateTime.now()
1619
                    .withDayOfMonth(1)
1620
                    .minusMonths(i);
1621
            monthValueMap.put(i, m.format(fmt));
1622
        }
1623
 
1624
        // 9) Assemble result with all brand-wise data
1625
        Map<String, Object> result = new HashMap<>();
1626
        result.put("totalIncome", totalIncome);
1627
        result.put("creditedIncome", creditedIncome);
1628
        result.put("pendingIncome", pendingIncome);
1629
        result.put("monthIndex", yearMonth);
1630
        result.put("monthValueMap", monthValueMap);
1631
 
1632
        // Include brand-wise data for detailed analysis
1633
        result.put("brandSet", brandSet);
1634
        result.put("totalAmountMap", totalAmountMap);
1635
        result.put("lastMonthPurchaseInMarginMap", lastMonthPurchaseInMarginMap);
1636
        result.put("lastMonthSaleMarginMap", lastMonthSaleMarginMap);
1637
        result.put("lastMonthPendingIncomeMap", lastMonthPendingIncomeMap);
1638
        result.put("additionalPurchasePayoutMap", additionalPurchasePayout);
1639
        result.put("additionalSalePayoutMap", additionSalePayout);
1640
        result.put("lastMonthFrontEndIncomeMap", lastMonthFrontEndIncomeMap);
1641
 
1642
        return result;
1643
    }
1644
 
22980 ashik.ali 1645
}