package com.lincfusion.udyamlinc.seed; import com.lincfusion.udyamlinc.auth.UdyamUser; import com.lincfusion.udyamlinc.auth.UdyamUserRepository; import com.lincfusion.udyamlinc.institution.*; import com.lincfusion.udyamlinc.master.DistrictRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Component; import java.util.List; import java.util.Optional; /** * NABARD's Regional Offices and the states each supervises. * *
Twenty-five offices covering twenty-six states. Two of them supervise more * than one state — Chandigarh takes Punjab and Haryana, Mumbai takes Maharashtra * and Goa — which is the whole reason the mapping is a table rather than a column. * *
Only six offices have a portfolio in the pilot: Bhopal, Guwahati, Patna, * Mumbai, Bengaluru and Jaipur. The other nineteen are seeded anyway. An empty * office is a true statement — NABARD supervises that state and this pilot has no * book there yet — whereas a missing office would make the national structure * look like it stops at the pilot's edge, and would strand any bank later opened * outside those six states. * *
Upserted per code, never guarded by {@code count() > 0}: the guard is why
* anything added after a database was first populated silently never arrives.
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class RegionalOfficeSeeder {
private final RegionalOfficeRepository officeRepository;
private final RegionalOfficeStateRepository officeStateRepository;
private final InstitutionRepository institutionRepository;
private final DistrictRepository districtRepository;
private final UdyamUserRepository userRepository;
private final PasswordEncoder passwordEncoder;
/** code, display name, city, office type, and the states it covers. */
private record OfficeSpec(String code, String name, String nameHi, String city,
String officeType, List Only the six with a book, because a login to an office with nothing in
* it demonstrates nothing and adds five empty consoles to the demo. The other
* nineteen offices still exist as data — they just have nobody to sign in as
* until a bank opens there.
*/
private void seedOfficeUsers() {
int written = 0;
for (RegionalOffice office : officeRepository.findByActiveTrueOrderByNameAsc()) {
// Skip offices with no supervised branches — resolved through the
// state mapping, the same path the tenancy filter uses.
boolean hasPortfolio = officeStateRepository.findByRegionalOfficeId(office.getId()).stream()
.anyMatch(s -> districtRepository.findByActiveTrue().stream()
.anyMatch(d -> d.getState().equals(s.getState())));
if (!hasPortfolio) continue;
String username = office.getCity().toLowerCase().replace(" ", "") + ".ro";
if (userRepository.findByUsernameIgnoreCase(username).isPresent()) continue;
userRepository.save(UdyamUser.builder()
.username(username)
.fullName(office.getName())
.password(passwordEncoder.encode(UdyamDataSeeder.DEFAULT_OFFICER_PASSWORD))
.role("RO_ADMIN")
// NABARD scope, not a scope of its own — the office is a
// narrowing of the apex tier, and the no-borrower rule comes
// with it rather than being granted again.
.scope("NABARD")
.institutionId(apexInstitutionId())
.regionalOfficeId(office.getId())
.branch(office.getCity())
.active(true)
.build());
written++;
}
if (written > 0) log.info("Seeded {} regional-office logins (password {})",
written, UdyamDataSeeder.DEFAULT_OFFICER_PASSWORD);
}
private Long apexInstitutionId() {
return institutionRepository.findByCode("NABARD").map(Institution::getId).orElse(null);
}
public void seed() {
int offices = 0, mappings = 0;
for (OfficeSpec spec : OFFICES) {
Optional