Subversion Repositories SmartDukaan

Rev

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