| Line 46... |
Line 46... |
| 46 |
Map<String, Double> salesParams,
|
46 |
Map<String, Double> salesParams,
|
| 47 |
Map<String, Double> purchaseParams,
|
47 |
Map<String, Double> purchaseParams,
|
| 48 |
Map<String, Double> creditParams) {
|
48 |
Map<String, Double> creditParams) {
|
| 49 |
Map<AgendaType, Decision> out = new LinkedHashMap<>();
|
49 |
Map<AgendaType, Decision> out = new LinkedHashMap<>();
|
| 50 |
|
50 |
|
| 51 |
// REVIVAL store: the Revival agenda owns the visit — every data-driven
|
51 |
// NOTE on REVIVAL stores: instances keep their own lifecycle here — the
|
| 52 |
// agenda EXCEPT loan overdue (CREDIT_DUES) is suppressed (AUTO instances
|
52 |
// rules evaluate on data regardless of activation state. Suppression for
|
| 53 |
// close; MANUAL ones are never touched by the cron).
|
53 |
// revival stores happens at the DISPLAY layer (visit agenda + checkout
|
| 54 |
Decision revivalSuppressed = new Decision(Action.CLOSE, "{\"reason\":\"REVIVAL\"}");
|
54 |
// remarks show only REVIVAL, CREDIT_DUES and MANUAL instances — see
|
| - |
|
55 |
// AgendaInstanceServiceImpl.filterVisibleForVisit).
|
| 55 |
|
56 |
|
| 56 |
// LOW_INVESTMENT — existing platform metric, PJP trigger at shortPct.
|
57 |
// LOW_INVESTMENT — existing platform metric, PJP trigger at shortPct.
|
| 57 |
if (in.revival) {
|
- |
|
| 58 |
out.put(AgendaType.LOW_INVESTMENT, revivalSuppressed);
|
- |
|
| 59 |
} else if (in.shortPercentage == null || in.minInvestment <= 0) {
|
58 |
if (in.shortPercentage == null || in.minInvestment <= 0) {
|
| 60 |
out.put(AgendaType.LOW_INVESTMENT, new Decision(Action.LEAVE, null));
|
59 |
out.put(AgendaType.LOW_INVESTMENT, new Decision(Action.LEAVE, null));
|
| 61 |
} else {
|
60 |
} else {
|
| 62 |
double shortPct = param(investParams, "shortPct", 50);
|
61 |
double shortPct = param(investParams, "shortPct", 50);
|
| 63 |
String metric = "{\"shortPct\":" + Math.round(in.shortPercentage) + "}";
|
62 |
String metric = "{\"shortPct\":" + Math.round(in.shortPercentage) + "}";
|
| 64 |
out.put(AgendaType.LOW_INVESTMENT, new Decision(
|
63 |
out.put(AgendaType.LOW_INVESTMENT, new Decision(
|
| 65 |
in.shortPercentage > shortPct ? Action.OPEN : Action.CLOSE, metric));
|
64 |
in.shortPercentage > shortPct ? Action.OPEN : Action.CLOSE, metric));
|
| 66 |
}
|
65 |
}
|
| 67 |
|
66 |
|
| 68 |
// LOW_SALES — hysteresis vs trailing baseline.
|
67 |
// LOW_SALES — hysteresis vs trailing baseline.
|
| 69 |
double monthlyBaseline = in.baselineAmt / (param(salesParams, "baselineDays", 90) / 30d);
|
68 |
double monthlyBaseline = in.baselineAmt / (param(salesParams, "baselineDays", 90) / 30d);
|
| 70 |
if (in.revival) {
|
- |
|
| 71 |
out.put(AgendaType.LOW_SALES, revivalSuppressed);
|
- |
|
| 72 |
} else if (in.storeActivatedRecently || monthlyBaseline <= 0) {
|
69 |
if (in.storeActivatedRecently || monthlyBaseline <= 0) {
|
| 73 |
out.put(AgendaType.LOW_SALES, new Decision(Action.LEAVE, null));
|
70 |
out.put(AgendaType.LOW_SALES, new Decision(Action.LEAVE, null));
|
| 74 |
} else {
|
71 |
} else {
|
| 75 |
double flagPct = param(salesParams, "flagPct", 40);
|
72 |
double flagPct = param(salesParams, "flagPct", 40);
|
| 76 |
double clearPct = param(salesParams, "clearPct", 75);
|
73 |
double clearPct = param(salesParams, "clearPct", 75);
|
| 77 |
String metric = "{\"current\":" + Math.round(in.currentAmt)
|
74 |
String metric = "{\"current\":" + Math.round(in.currentAmt)
|
| Line 84... |
Line 81... |
| 84 |
out.put(AgendaType.LOW_SALES, new Decision(Action.LEAVE, metric));
|
81 |
out.put(AgendaType.LOW_SALES, new Decision(Action.LEAVE, metric));
|
| 85 |
}
|
82 |
}
|
| 86 |
}
|
83 |
}
|
| 87 |
|
84 |
|
| 88 |
// LOW_PURCHASE — days since last billed purchase.
|
85 |
// LOW_PURCHASE — days since last billed purchase.
|
| 89 |
if (in.revival) {
|
- |
|
| 90 |
out.put(AgendaType.LOW_PURCHASE, revivalSuppressed);
|
- |
|
| 91 |
} else {
|
86 |
{
|
| 92 |
double gapDays = param(purchaseParams, "gapDays", 15);
|
87 |
double gapDays = param(purchaseParams, "gapDays", 15);
|
| 93 |
boolean flag = in.lastBillDaysAgo == null || in.lastBillDaysAgo >= gapDays;
|
88 |
boolean flag = in.lastBillDaysAgo == null || in.lastBillDaysAgo >= gapDays;
|
| 94 |
String metric = "{\"gapDays\":" + (in.lastBillDaysAgo == null ? -1 : in.lastBillDaysAgo) + "}";
|
89 |
String metric = "{\"gapDays\":" + (in.lastBillDaysAgo == null ? -1 : in.lastBillDaysAgo) + "}";
|
| 95 |
out.put(AgendaType.LOW_PURCHASE, new Decision(flag ? Action.OPEN : Action.CLOSE, metric));
|
90 |
out.put(AgendaType.LOW_PURCHASE, new Decision(flag ? Action.OPEN : Action.CLOSE, metric));
|
| 96 |
}
|
91 |
}
|