| Line 357... |
Line 357... |
| 357 |
});
|
357 |
});
|
| 358 |
}
|
358 |
}
|
| 359 |
|
359 |
|
| 360 |
// Open agenda instances (AUTO + MANUAL) per party — the modal pre-selects
|
360 |
// Open agenda instances (AUTO + MANUAL) per party — the modal pre-selects
|
| 361 |
// these; AUTO ones are badged and close only when their metric normalizes.
|
361 |
// these; AUTO ones are badged and close only when their metric normalizes.
|
| - |
|
362 |
// Visibility rule: for a REVIVAL store only REVIVAL/CREDIT_DUES/MANUAL
|
| - |
|
363 |
// agendas are populated (the rest keep their lifecycle but stay hidden).
|
| 362 |
List<Integer> partyIds = new ArrayList<>();
|
364 |
List<Integer> partyIds = new ArrayList<>();
|
| 363 |
for (Map<String, Object> p : parties) partyIds.add((Integer) p.get("fofoStoreId"));
|
365 |
for (Map<String, Object> p : parties) partyIds.add((Integer) p.get("fofoStoreId"));
|
| 364 |
Map<Integer, List<Map<String, Object>>> openAgendasByFofo = new HashMap<>();
|
366 |
Map<Integer, List<AgendaInstance>> openByFofo = new HashMap<>();
|
| 365 |
for (AgendaInstance ai : agendaInstanceRepository.selectOpenByFofoIds(partyIds)) {
|
367 |
for (AgendaInstance ai : agendaInstanceRepository.selectOpenByFofoIds(partyIds)) {
|
| - |
|
368 |
openByFofo.computeIfAbsent(ai.getFofoId(), k -> new ArrayList<>()).add(ai);
|
| - |
|
369 |
}
|
| - |
|
370 |
Map<Integer, List<Map<String, Object>>> openAgendasByFofo = new HashMap<>();
|
| - |
|
371 |
for (Map.Entry<Integer, List<AgendaInstance>> e : openByFofo.entrySet()) {
|
| - |
|
372 |
List<Map<String, Object>> visible = new ArrayList<>();
|
| - |
|
373 |
for (AgendaInstance ai : agendaInstanceService.filterVisibleForVisit(e.getValue())) {
|
| 366 |
Map<String, Object> m = new HashMap<>();
|
374 |
Map<String, Object> m = new HashMap<>();
|
| 367 |
m.put("id", ai.getId());
|
375 |
m.put("id", ai.getId());
|
| 368 |
m.put("agendaType", ai.getAgendaType());
|
376 |
m.put("agendaType", ai.getAgendaType());
|
| 369 |
m.put("label", labelFor(ai.getAgendaType()));
|
377 |
m.put("label", labelFor(ai.getAgendaType()));
|
| 370 |
m.put("source", ai.getSource());
|
378 |
m.put("source", ai.getSource());
|
| 371 |
m.put("openedOn", ai.getOpenedOn() != null ? ai.getOpenedOn().toLocalDate().toString() : null);
|
379 |
m.put("openedOn", ai.getOpenedOn() != null ? ai.getOpenedOn().toLocalDate().toString() : null);
|
| - |
|
380 |
visible.add(m);
|
| - |
|
381 |
}
|
| 372 |
openAgendasByFofo.computeIfAbsent(ai.getFofoId(), k -> new ArrayList<>()).add(m);
|
382 |
openAgendasByFofo.put(e.getKey(), visible);
|
| 373 |
}
|
383 |
}
|
| 374 |
for (Map<String, Object> p : parties) {
|
384 |
for (Map<String, Object> p : parties) {
|
| 375 |
p.put("openAgendas", openAgendasByFofo.getOrDefault((Integer) p.get("fofoStoreId"), new ArrayList<>()));
|
385 |
p.put("openAgendas", openAgendasByFofo.getOrDefault((Integer) p.get("fofoStoreId"), new ArrayList<>()));
|
| 376 |
}
|
386 |
}
|
| 377 |
|
387 |
|
| 378 |
Map<String, Object> result = new HashMap<>();
|
388 |
Map<String, Object> result = new HashMap<>();
|
| 379 |
result.put("dtrUserId", dtrUserId);
|
389 |
result.put("dtrUserId", dtrUserId);
|
| 380 |
result.put("authUserId", authUserId);
|
390 |
result.put("authUserId", authUserId);
|
| 381 |
result.put("userName", au.getFirstName() + " " + au.getLastName());
|
391 |
result.put("userName", au.getFirstName() + " " + au.getLastName());
|
| 382 |
result.put("parties", parties);
|
392 |
result.put("parties", parties);
|
| - |
|
393 |
// Only non-auto agendas are manually assignable; auto ones surface via
|
| - |
|
394 |
// openAgendas (chips) and are woven into task_name server-side on submit.
|
| 383 |
result.put("agendaOptions", com.spice.profitmandi.dao.enumuration.dtr.VisitAgenda.labels());
|
395 |
result.put("agendaOptions", AgendaType.manualAssignableLabels());
|
| 384 |
return responseSender.ok(result);
|
396 |
return responseSender.ok(result);
|
| 385 |
}
|
397 |
}
|
| 386 |
|
398 |
|
| 387 |
// agenda_type holds the enum NAME (e.g. LOW_SALES); tolerate unknown values.
|
399 |
// agenda_type holds the enum NAME (e.g. LOW_SALES); tolerate unknown values.
|
| 388 |
private String labelFor(String agendaTypeName) {
|
400 |
private String labelFor(String agendaTypeName) {
|
| Line 480... |
Line 492... |
| 480 |
}
|
492 |
}
|
| 481 |
if (agendas.isEmpty()) {
|
493 |
if (agendas.isEmpty()) {
|
| 482 |
String single = (String) p.get("agenda");
|
494 |
String single = (String) p.get("agenda");
|
| 483 |
if (single != null && !single.trim().isEmpty()) agendas.add(single.trim());
|
495 |
if (single != null && !single.trim().isEmpty()) agendas.add(single.trim());
|
| 484 |
}
|
496 |
}
|
| 485 |
if (agendas.isEmpty()) agendas.add("Visit");
|
497 |
// Compose the final agenda set: visible open instances first (auto
|
| 486 |
String agendaJoined = String.join(", ", agendas);
|
498 |
// agendas populate themselves — the planner never assigns them),
|
| 487 |
|
- |
|
| 488 |
// Lifecycle: any picked agenda without an open instance becomes a
|
499 |
// then the picked manual-assignable agendas. Picked labels of
|
| 489 |
// MANUAL instance. open() no-ops when one is already OPEN (AUTO or
|
500 |
// auto-rule types are ignored (server-authoritative guard).
|
| 490 |
// MANUAL), so pre-existing auto agendas are left untouched.
|
501 |
LinkedHashSet<String> finalAgendas = new LinkedHashSet<>();
|
| - |
|
502 |
for (AgendaInstance ai : agendaInstanceService.filterVisibleForVisit(
|
| - |
|
503 |
agendaInstanceRepository.selectOpenByFofoId(fofoStoreId))) {
|
| - |
|
504 |
finalAgendas.add(labelFor(ai.getAgendaType()));
|
| - |
|
505 |
}
|
| 491 |
for (String label : agendas) {
|
506 |
for (String label : agendas) {
|
| 492 |
AgendaType type = AgendaType.fromLabel(label);
|
507 |
AgendaType type = AgendaType.fromLabel(label);
|
| 493 |
if (type == null) continue; // "Visit" default — not lifecycle-tracked
|
508 |
if (type == null) continue; // free text / legacy "Visit" — dropped
|
| - |
|
509 |
if (!type.isManualAssignable()) continue; // auto agendas: cron-only
|
| 494 |
agendaInstanceService.open(fofoStoreId, type.name(), AgendaSource.MANUAL, operatorAuthId, null);
|
510 |
agendaInstanceService.open(fofoStoreId, type.name(), AgendaSource.MANUAL, operatorAuthId, null);
|
| - |
|
511 |
finalAgendas.add(label);
|
| 495 |
}
|
512 |
}
|
| - |
|
513 |
if (finalAgendas.isEmpty()) finalAgendas.add("Visit");
|
| - |
|
514 |
String agendaJoined = String.join(", ", finalAgendas);
|
| 496 |
|
515 |
|
| 497 |
String visitLocation = (lat != null && lng != null && !lat.isEmpty() && !lng.isEmpty())
|
516 |
String visitLocation = (lat != null && lng != null && !lat.isEmpty() && !lng.isEmpty())
|
| 498 |
? (lat + "," + lng) : "0.0000,0.0000";
|
517 |
? (lat + "," + lng) : "0.0000,0.0000";
|
| 499 |
|
518 |
|
| 500 |
String displayName = (outletName != null && !outletName.isEmpty()) ? outletName : ("Store #" + fofoStoreId);
|
519 |
String displayName = (outletName != null && !outletName.isEmpty()) ? outletName : ("Store #" + fofoStoreId);
|