| Line 2117... |
Line 2117... |
| 2117 |
LocalDateTime now = LocalDateTime.now();
|
2117 |
LocalDateTime now = LocalDateTime.now();
|
| 2118 |
LocalDateTime thirtyDaysAgo = now.minusDays(30);
|
2118 |
LocalDateTime thirtyDaysAgo = now.minusDays(30);
|
| 2119 |
LocalDateTime sixtyDaysAgo = now.minusDays(60);
|
2119 |
LocalDateTime sixtyDaysAgo = now.minusDays(60);
|
| 2120 |
long threshold = 99_999L;
|
2120 |
long threshold = 99_999L;
|
| 2121 |
|
2121 |
|
| - |
|
2122 |
// Include REVIVAL now so previously-downgraded stores can be promoted back to ACTIVE
|
| - |
|
2123 |
// when they resume billing above the threshold in the last 30 days.
|
| 2122 |
List<FofoStore> candidates = fofoStoreRepository.selectAllFranchiseStores().stream()
|
2124 |
List<FofoStore> candidates = fofoStoreRepository.selectAllFranchiseStores().stream()
|
| 2123 |
.filter(s -> s.isActive() && !s.isInternal() && !s.isClosed())
|
2125 |
.filter(s -> s.isActive() && !s.isInternal() && !s.isClosed())
|
| 2124 |
.filter(s -> s.getActivationType() == ActivationType.ACTIVE
|
2126 |
.filter(s -> s.getActivationType() == ActivationType.ACTIVE
|
| 2125 |
|| s.getActivationType() == ActivationType.FOCUS)
|
2127 |
|| s.getActivationType() == ActivationType.FOCUS
|
| - |
|
2128 |
|| s.getActivationType() == ActivationType.REVIVAL)
|
| 2126 |
.collect(Collectors.toList());
|
2129 |
.collect(Collectors.toList());
|
| 2127 |
|
2130 |
|
| 2128 |
if (candidates.isEmpty()) {
|
2131 |
if (candidates.isEmpty()) {
|
| 2129 |
LOGGER.info("updatePartnerActivationTypeByMonthlySale: no candidate stores");
|
2132 |
LOGGER.info("updatePartnerActivationTypeByMonthlySale: no candidate stores");
|
| 2130 |
return;
|
2133 |
return;
|
| Line 2134... |
Line 2137... |
| 2134 |
Set<Integer> met30 = orderRepository.selectFofoIdsWithMtdBillingAboveThreshold(ids, thirtyDaysAgo, now, threshold);
|
2137 |
Set<Integer> met30 = orderRepository.selectFofoIdsWithMtdBillingAboveThreshold(ids, thirtyDaysAgo, now, threshold);
|
| 2135 |
Set<Integer> met60 = orderRepository.selectFofoIdsWithMtdBillingAboveThreshold(ids, sixtyDaysAgo, now, threshold);
|
2138 |
Set<Integer> met60 = orderRepository.selectFofoIdsWithMtdBillingAboveThreshold(ids, sixtyDaysAgo, now, threshold);
|
| 2136 |
|
2139 |
|
| 2137 |
int toFocus = 0;
|
2140 |
int toFocus = 0;
|
| 2138 |
int toRevival = 0;
|
2141 |
int toRevival = 0;
|
| - |
|
2142 |
int toActive = 0;
|
| 2139 |
for (FofoStore store : candidates) {
|
2143 |
for (FofoStore store : candidates) {
|
| 2140 |
int id = store.getId();
|
2144 |
int id = store.getId();
|
| 2141 |
boolean below30 = !met30.contains(id);
|
2145 |
boolean above30 = met30.contains(id);
|
| - |
|
2146 |
boolean below30 = !above30;
|
| 2142 |
boolean below60 = !met60.contains(id);
|
2147 |
boolean below60 = !met60.contains(id);
|
| 2143 |
ActivationType current = store.getActivationType();
|
2148 |
ActivationType current = store.getActivationType();
|
| 2144 |
ActivationType target = current;
|
2149 |
ActivationType target = current;
|
| 2145 |
|
2150 |
|
| - |
|
2151 |
// Promotion — asymmetric windows by current status:
|
| - |
|
2152 |
// FOCUS → ACTIVE if billed > ₹99,999 in the last 30 days (recent activity required)
|
| - |
|
2153 |
// REVIVAL → ACTIVE if billed > ₹99,999 in the last 60 days (deeper trouble, so any
|
| - |
|
2154 |
// sign of life in the last 2 months earns a promotion)
|
| - |
|
2155 |
// Evaluated ahead of the downgrade rules so a recently-billing REVIVAL isn't held at
|
| - |
|
2156 |
// REVIVAL by the below60 rule below.
|
| - |
|
2157 |
if (current == ActivationType.FOCUS && above30) {
|
| - |
|
2158 |
target = ActivationType.ACTIVE;
|
| - |
|
2159 |
} else if (current == ActivationType.REVIVAL && met60.contains(id)) {
|
| - |
|
2160 |
target = ActivationType.ACTIVE;
|
| 2146 |
if (below60) {
|
2161 |
} else if (below60) {
|
| 2147 |
target = ActivationType.REVIVAL;
|
2162 |
target = ActivationType.REVIVAL;
|
| 2148 |
} else if (below30 && current == ActivationType.ACTIVE) {
|
2163 |
} else if (below30 && current == ActivationType.ACTIVE) {
|
| 2149 |
target = ActivationType.FOCUS;
|
2164 |
target = ActivationType.FOCUS;
|
| 2150 |
}
|
2165 |
}
|
| 2151 |
|
2166 |
|
| 2152 |
if (target != current) {
|
2167 |
if (target != current) {
|
| - |
|
2168 |
// Safety guard only applies to downgrades — never auto-downgrade a store that
|
| - |
|
2169 |
// has never billed yet. Promotions to ACTIVE always allowed (billing observed).
|
| - |
|
2170 |
if (target != ActivationType.ACTIVE) {
|
| 2153 |
LocalDateTime firstBillingDate = transactionRepository.getFirstBillingDate(id);
|
2171 |
LocalDateTime firstBillingDate = transactionRepository.getFirstBillingDate(id);
|
| 2154 |
if (firstBillingDate == null) {
|
2172 |
if (firstBillingDate == null) {
|
| 2155 |
LOGGER.info("Skip auto-downgrade fofoId={} code={}: first billing pending",
|
2173 |
LOGGER.info("Skip auto-downgrade fofoId={} code={}: first billing pending",
|
| 2156 |
id, store.getCode());
|
2174 |
id, store.getCode());
|
| 2157 |
continue;
|
2175 |
continue;
|
| - |
|
2176 |
}
|
| 2158 |
}
|
2177 |
}
|
| 2159 |
LOGGER.info("Auto-downgrade fofoId={} code={} from {} to {} (below30={}, below60={})",
|
2178 |
LOGGER.info("Auto-{} fofoId={} code={} from {} to {} (above30={}, below60={})",
|
| - |
|
2179 |
target == ActivationType.ACTIVE ? "promote" : "downgrade",
|
| 2160 |
id, store.getCode(), current, target, below30, below60);
|
2180 |
id, store.getCode(), current, target, above30, below60);
|
| 2161 |
store.setActivationType(target);
|
2181 |
store.setActivationType(target);
|
| 2162 |
fofoStoreRepository.persist(store);
|
2182 |
fofoStoreRepository.persist(store);
|
| 2163 |
if (target == ActivationType.FOCUS) {
|
2183 |
if (target == ActivationType.FOCUS) {
|
| 2164 |
toFocus++;
|
2184 |
toFocus++;
|
| 2165 |
} else {
|
2185 |
} else if (target == ActivationType.REVIVAL) {
|
| 2166 |
toRevival++;
|
2186 |
toRevival++;
|
| - |
|
2187 |
} else if (target == ActivationType.ACTIVE) {
|
| - |
|
2188 |
toActive++;
|
| 2167 |
}
|
2189 |
}
|
| 2168 |
}
|
2190 |
}
|
| 2169 |
}
|
2191 |
}
|
| 2170 |
LOGGER.info("updatePartnerActivationTypeByMonthlySale done: scanned={}, toFocus={}, toRevival={}",
|
2192 |
LOGGER.info("updatePartnerActivationTypeByMonthlySale done: scanned={}, toFocus={}, toRevival={}, toActive={}",
|
| 2171 |
candidates.size(), toFocus, toRevival);
|
2193 |
candidates.size(), toFocus, toRevival, toActive);
|
| 2172 |
}
|
2194 |
}
|
| 2173 |
|
2195 |
|
| 2174 |
public void sendAgeingReport() throws Exception {
|
2196 |
public void sendAgeingReport() throws Exception {
|
| 2175 |
sendAgeingReport("kamini.sharma@smartdukaan.com", "tarun.verma@smartdukaan.com", "niranjan.kala@smartdukaan.com", "kuldeep.kumar@smartdukaan.com");
|
2197 |
sendAgeingReport("kamini.sharma@smartdukaan.com", "tarun.verma@smartdukaan.com", "niranjan.kala@smartdukaan.com", "kuldeep.kumar@smartdukaan.com");
|
| 2176 |
}
|
2198 |
}
|