Subversion Repositories SmartDukaan

Rev

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