| Line 37... |
Line 37... |
| 37 |
import org.springframework.beans.factory.annotation.Autowired;
|
37 |
import org.springframework.beans.factory.annotation.Autowired;
|
| 38 |
import org.springframework.beans.factory.annotation.Qualifier;
|
38 |
import org.springframework.beans.factory.annotation.Qualifier;
|
| 39 |
import org.springframework.cache.annotation.Cacheable;
|
39 |
import org.springframework.cache.annotation.Cacheable;
|
| 40 |
import org.springframework.mail.javamail.JavaMailSender;
|
40 |
import org.springframework.mail.javamail.JavaMailSender;
|
| 41 |
import org.springframework.stereotype.Component;
|
41 |
import org.springframework.stereotype.Component;
|
| - |
|
42 |
import org.springframework.transaction.annotation.Transactional;
|
| 42 |
|
43 |
|
| 43 |
import java.nio.charset.StandardCharsets;
|
44 |
import java.nio.charset.StandardCharsets;
|
| 44 |
import java.time.LocalDate;
|
45 |
import java.time.LocalDate;
|
| 45 |
import java.time.LocalDateTime;
|
46 |
import java.time.LocalDateTime;
|
| 46 |
import java.time.YearMonth;
|
47 |
import java.time.YearMonth;
|
| Line 304... |
Line 305... |
| 304 |
|
305 |
|
| 305 |
}
|
306 |
}
|
| 306 |
|
307 |
|
| 307 |
@SuppressWarnings("unchecked")
|
308 |
@SuppressWarnings("unchecked")
|
| 308 |
@Override
|
309 |
@Override
|
| - |
|
310 |
@Transactional(rollbackFor = Throwable.class)
|
| 309 |
public Map<String, Object> updateRetailerDetails(UpdateRetailerRequest updateRetailerRequest) throws
|
311 |
public Map<String, Object> updateRetailerDetails(UpdateRetailerRequest updateRetailerRequest) throws
|
| 310 |
ProfitMandiBusinessException {
|
312 |
ProfitMandiBusinessException {
|
| 311 |
Map<String, Object> map = this.getByEmailIdOrMobileNumber(updateRetailerRequest.getEmailIdOrMobileNumber());
|
313 |
Map<String, Object> map = this.getByEmailIdOrMobileNumber(updateRetailerRequest.getEmailIdOrMobileNumber());
|
| 312 |
User dtrUser = (User) map.get("user");
|
314 |
User dtrUser = (User) map.get("user");
|
| 313 |
|
315 |
|
| - |
|
316 |
if (updateRetailerRequest.isFofo()) {
|
| - |
|
317 |
Retailer resolvedRetailer = (Retailer) map.get("retailer");
|
| - |
|
318 |
if (resolvedRetailer == null) {
|
| - |
|
319 |
// This save would mint a brand-new identity chain. Mandate: a partner
|
| - |
|
320 |
// gets a new store code only after the old store is closed, and the
|
| - |
|
321 |
// re-onboarding must reuse the partner's real email (takeover below) —
|
| - |
|
322 |
// never a variant email that forks a duplicate chain.
|
| - |
|
323 |
this.guardAgainstDuplicatePartnerChain(updateRetailerRequest);
|
| - |
|
324 |
} else if (updateRetailerRequest.isActive()) {
|
| - |
|
325 |
FofoStore existingStore = this.selectStoreOrNull(resolvedRetailer.getId());
|
| - |
|
326 |
if (existingStore != null && existingStore.isClosed()) {
|
| - |
|
327 |
this.takeoverClosedStoreIdentity(existingStore, map);
|
| - |
|
328 |
}
|
| - |
|
329 |
}
|
| - |
|
330 |
}
|
| - |
|
331 |
|
| 314 |
dtrUser = this.createUser(dtrUser, updateRetailerRequest);
|
332 |
dtrUser = this.createUser(dtrUser, updateRetailerRequest);
|
| 315 |
|
333 |
|
| 316 |
map.put("user", dtrUser);
|
334 |
map.put("user", dtrUser);
|
| 317 |
List<UserRole> userRoles = (List<UserRole>) map.get("userRoles");
|
335 |
List<UserRole> userRoles = (List<UserRole>) map.get("userRoles");
|
| 318 |
Role roleUser = roleRepository.selectByName(RoleType.USER.toString());
|
336 |
Role roleUser = roleRepository.selectByName(RoleType.USER.toString());
|
| Line 320... |
Line 338... |
| 320 |
Retailer retailer = (Retailer) map.get("retailer");
|
338 |
Retailer retailer = (Retailer) map.get("retailer");
|
| 321 |
retailer = this.updateRetailer(dtrUser, retailer, updateRetailerRequest);
|
339 |
retailer = this.updateRetailer(dtrUser, retailer, updateRetailerRequest);
|
| 322 |
|
340 |
|
| 323 |
map.put("retailer", retailer);
|
341 |
map.put("retailer", retailer);
|
| 324 |
|
342 |
|
| 325 |
// Ensure UserAccount links new dtr user to retailer (handles case where
|
343 |
// Ensure the dtr login's bridge rows point at the current identity. Repairs
|
| 326 |
// dtr.user was deleted and re-created with a new ID)
|
344 |
// recreated logins and repoints the login after a closed-store takeover.
|
| - |
|
345 |
userAccountRepository.upsert(dtrUser.getId(), AccountType.saholic, retailer.getId());
|
| 327 |
try {
|
346 |
try {
|
| 328 |
userAccountRepository.selectSaholicByUserId(dtrUser.getId());
|
347 |
com.spice.profitmandi.dao.entity.user.User identity = userUserRepository.selectById(retailer.getId());
|
| 329 |
} catch (ProfitMandiBusinessException e) {
|
- |
|
| 330 |
try {
|
- |
|
| 331 |
UserAccount ua = new UserAccount();
|
- |
|
| 332 |
ua.setAccountKey(retailer.getId());
|
348 |
if (identity.getActiveCartId() > 0) {
|
| 333 |
ua.setUserId(dtrUser.getId());
|
- |
|
| 334 |
ua.setType(AccountType.saholic);
|
- |
|
| 335 |
userAccountRepository.persist(ua);
|
- |
|
| 336 |
} catch (Exception ex) {
|
- |
|
| 337 |
LOGGER.error("Error creating saholic UserAccount for userId: {}", dtrUser.getId(), ex);
|
349 |
userAccountRepository.upsert(dtrUser.getId(), AccountType.cartId, identity.getActiveCartId());
|
| 338 |
}
|
350 |
}
|
| - |
|
351 |
} catch (ProfitMandiBusinessException e) {
|
| - |
|
352 |
LOGGER.error("Error ensuring cartId UserAccount for userId: {}", dtrUser.getId(), e);
|
| 339 |
}
|
353 |
}
|
| 340 |
|
354 |
|
| 341 |
List<String> retailerBlockBrands = retailerBlockBrandsRepository.selectAllByRetailer(retailer.getId()).stream().map(x -> x.getBlockBrands()).collect(Collectors.toList());
|
355 |
List<String> retailerBlockBrands = retailerBlockBrandsRepository.selectAllByRetailer(retailer.getId()).stream().map(x -> x.getBlockBrands()).collect(Collectors.toList());
|
| 342 |
|
356 |
|
| 343 |
LOGGER.info("retailerBlockBrands" + retailerBlockBrands);
|
357 |
LOGGER.info("retailerBlockBrands" + retailerBlockBrands);
|
| Line 408... |
Line 422... |
| 408 |
|
422 |
|
| 409 |
return map;
|
423 |
return map;
|
| 410 |
|
424 |
|
| 411 |
}
|
425 |
}
|
| 412 |
|
426 |
|
| - |
|
427 |
private FofoStore selectStoreOrNull(int retailerId) {
|
| - |
|
428 |
try {
|
| - |
|
429 |
return fofoStoreRepository.selectByRetailerId(retailerId);
|
| - |
|
430 |
} catch (ProfitMandiBusinessException e) {
|
| - |
|
431 |
return null;
|
| - |
|
432 |
}
|
| - |
|
433 |
}
|
| - |
|
434 |
|
| - |
|
435 |
private void guardAgainstDuplicatePartnerChain(UpdateRetailerRequest updateRetailerRequest)
|
| - |
|
436 |
throws ProfitMandiBusinessException {
|
| - |
|
437 |
User byMobile = null;
|
| - |
|
438 |
try {
|
| - |
|
439 |
byMobile = userRepository.selectByMobileNumber(updateRetailerRequest.getUserMobileNumber());
|
| - |
|
440 |
} catch (ProfitMandiBusinessException e) {
|
| - |
|
441 |
// no dtr user with this mobile
|
| - |
|
442 |
}
|
| - |
|
443 |
if (byMobile != null) {
|
| - |
|
444 |
Integer accountKey = userAccountRepository.selectSaholicAccountKeySafe(byMobile.getId());
|
| - |
|
445 |
FofoStore store = accountKey != null ? this.selectStoreOrNull(accountKey) : null;
|
| - |
|
446 |
if (store != null) {
|
| - |
|
447 |
if (!store.isClosed()) {
|
| - |
|
448 |
throw new ProfitMandiBusinessException("Open store exists", store.getCode(),
|
| - |
|
449 |
"Partner mobile " + updateRetailerRequest.getUserMobileNumber()
|
| - |
|
450 |
+ " already owns open store " + store.getCode()
|
| - |
|
451 |
+ ". Close it first, or use email-change to keep the same code.");
|
| - |
|
452 |
}
|
| - |
|
453 |
throw new ProfitMandiBusinessException("Closed store exists", store.getCode(),
|
| - |
|
454 |
"Old store " + store.getCode() + " is closed. Re-onboard using the partner's existing email "
|
| - |
|
455 |
+ byMobile.getEmailId() + " and a new code will be issued automatically.");
|
| - |
|
456 |
}
|
| - |
|
457 |
}
|
| - |
|
458 |
if (!updateRetailerRequest.isAllowAdditionalOutlet()) {
|
| - |
|
459 |
List<FofoStore> openGstStores = fofoStoreRepository.selectAllOpenByGstNumber(updateRetailerRequest.getGstNumber());
|
| - |
|
460 |
if (!openGstStores.isEmpty()) {
|
| - |
|
461 |
String codes = openGstStores.stream().map(FofoStore::getCode).collect(Collectors.joining(", "));
|
| - |
|
462 |
throw new ProfitMandiBusinessException("Open store exists for GST", codes,
|
| - |
|
463 |
"GST " + updateRetailerRequest.getGstNumber() + " already has open store(s) " + codes
|
| - |
|
464 |
+ ". Close the old store first, or tick 'Additional outlet for same GST' if this is genuinely a new outlet.");
|
| - |
|
465 |
}
|
| - |
|
466 |
}
|
| - |
|
467 |
}
|
| - |
|
468 |
|
| - |
|
469 |
private void takeoverClosedStoreIdentity(FofoStore oldStore, Map<String, Object> map) {
|
| - |
|
470 |
// Mandate: closed stores are never reopened. Re-onboarding with the partner's
|
| - |
|
471 |
// real contacts issues a fresh code on the same dtr login: free the old
|
| - |
|
472 |
// identity's email so the new user.user can take it over, then drop the old
|
| - |
|
473 |
// chain from the resolution map so the save proceeds as a fresh onboarding.
|
| - |
|
474 |
try {
|
| - |
|
475 |
com.spice.profitmandi.dao.entity.user.User oldIdentity = userUserRepository.selectById(oldStore.getId());
|
| - |
|
476 |
String tombstone = "closed." + oldStore.getId() + "." + oldIdentity.getEmailId();
|
| - |
|
477 |
if (tombstone.length() > 128) {
|
| - |
|
478 |
tombstone = tombstone.substring(0, 128);
|
| - |
|
479 |
}
|
| - |
|
480 |
oldIdentity.setEmailId(tombstone);
|
| - |
|
481 |
} catch (ProfitMandiBusinessException e) {
|
| - |
|
482 |
LOGGER.error("Takeover: identity not found for closed store {}", oldStore.getId(), e);
|
| - |
|
483 |
}
|
| - |
|
484 |
LOGGER.info("Takeover: closed store {} ({}) — issuing new code on the same login", oldStore.getCode(), oldStore.getId());
|
| - |
|
485 |
map.remove("retailer");
|
| - |
|
486 |
map.remove("retailerAddress");
|
| - |
|
487 |
map.remove("shops");
|
| - |
|
488 |
map.remove("fofoStore");
|
| - |
|
489 |
}
|
| - |
|
490 |
|
| 413 |
private void createDefaultPaymentOption(int fofoId) {
|
491 |
private void createDefaultPaymentOption(int fofoId) {
|
| 414 |
List<Integer> paymentOptionIds = fofoPartnerPaymentOptionRepository.selectPaymentOptionIdsByFofoId(fofoId);
|
492 |
List<Integer> paymentOptionIds = fofoPartnerPaymentOptionRepository.selectPaymentOptionIdsByFofoId(fofoId);
|
| 415 |
if (paymentOptionIds.isEmpty()) {
|
493 |
if (paymentOptionIds.isEmpty()) {
|
| 416 |
PaymentOption paymentOption = null;
|
494 |
PaymentOption paymentOption = null;
|
| 417 |
try {
|
495 |
try {
|
| Line 492... |
Line 570... |
| 492 |
saholicUser.setName(retailerName);
|
570 |
saholicUser.setName(retailerName);
|
| 493 |
saholicUser.setActiveCartId(cart.getId());
|
571 |
saholicUser.setActiveCartId(cart.getId());
|
| 494 |
saholicUser.setCreateTimestamp(LocalDateTime.now());
|
572 |
saholicUser.setCreateTimestamp(LocalDateTime.now());
|
| 495 |
userUserRepository.persist(saholicUser);
|
573 |
userUserRepository.persist(saholicUser);
|
| 496 |
|
574 |
|
| 497 |
UserAccount ua = new UserAccount();
|
- |
|
| 498 |
ua.setAccountKey(saholicUser.getId());
|
575 |
userAccountRepository.upsert(user.getId(), AccountType.saholic, saholicUser.getId());
|
| 499 |
ua.setUserId(user.getId());
|
- |
|
| 500 |
ua.setType(AccountType.saholic);
|
- |
|
| 501 |
userAccountRepository.persist(ua);
|
- |
|
| 502 |
|
- |
|
| 503 |
UserAccount ua2 = new UserAccount();
|
- |
|
| 504 |
ua2.setAccountKey(saholicUser.getActiveCartId());
|
576 |
userAccountRepository.upsert(user.getId(), AccountType.cartId, saholicUser.getActiveCartId());
|
| 505 |
ua2.setUserId(user.getId());
|
- |
|
| 506 |
ua2.setType(AccountType.cartId);
|
- |
|
| 507 |
userAccountRepository.persist(ua2);
|
- |
|
| 508 |
LOGGER.info("created....");
|
577 |
LOGGER.info("created....");
|
| 509 |
}
|
578 |
}
|
| 510 |
return saholicUser.getId();
|
579 |
return saholicUser.getId();
|
| 511 |
}
|
580 |
}
|
| 512 |
|
581 |
|