Subversion Repositories SmartDukaan

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
37579 amit 1
package com.spice.profitmandi.web.offercircular;
2
 
3
import static org.junit.Assert.assertEquals;
4
import static org.junit.Assert.assertNotEquals;
5
import static org.junit.Assert.assertTrue;
6
 
7
import java.time.LocalDate;
8
 
9
import org.junit.Test;
10
 
11
import com.spice.profitmandi.web.offercircular.WebOfferSyncService.Line;
12
import com.spice.profitmandi.web.offercircular.WebOfferSyncService.ModelOffer;
13
 
14
/**
15
 * Guards the consolidated badge - the one offer line a partner reads on a product card.
16
 *
17
 * Before consolidation a model carried one badge per circular row that named it; Edge 60
18
 * Pro 12+256 had five, and the partner had to reconcile them. These cases are taken from
19
 * the Sep'26 circular, because the failures that matter here are all real ones: a bank
20
 * that does not offer a scheme, a tenure that belongs to a different bank's offer, an
21
 * amount that stops earlier than the badge does.
22
 *
23
 * Constructed with no collaborators - the rendering must not need Spring or a database.
24
 */
25
public class ModelOfferTest {
26
 
27
    private final WebOfferSyncService service = new WebOfferSyncService(null, null);
28
 
29
    private static final LocalDate SEP_1 = LocalDate.of(2026, 9, 1);
30
    private static final LocalDate SEP_16 = LocalDate.of(2026, 9, 16);
31
    private static final LocalDate SEP_20 = LocalDate.of(2026, 9, 20);
32
    private static final LocalDate SEP_26 = LocalDate.of(2026, 9, 26);
33
 
34
    private static Line cashback(String mode, String amount, String banks,
35
                                 String tenures, LocalDate end) {
36
        Line line = new Line();
37
        line.txnMode = mode;
38
        line.calcType = "FLAT";
39
        line.flatAmount = new java.math.BigDecimal(amount);
40
        line.timing = "INSTANT";
41
        line.banks = banks;
42
        line.tenures = tenures;
43
        line.start = SEP_1;
44
        line.end = end;
45
        return line;
46
    }
47
 
48
    private static Line scheme(String tenures, String banks) {
49
        Line line = new Line();
50
        line.timing = "INSTANT";
51
        line.banks = banks;
52
        line.tenures = tenures;
53
        line.start = SEP_1;
54
        line.end = SEP_20;
55
        return line;
56
    }
57
 
58
    private static ModelOffer model(String brand, Line... lines) {
59
        ModelOffer offer = new ModelOffer();
60
        offer.brand = brand;
61
        for (Line line : lines) {
62
            offer.add(line);
63
        }
64
        return offer;
65
    }
66
 
67
    // ------------------------------------------------------------------ Edge 60 Pro
68
 
69
    /**
70
     * Motorola Edge 60 Pro (12GB 256GB), Sep'26 page 9 - five badges before, one now.
71
     *
72
     * The banks differ on every line, so none can be hoisted: the EMI cashback is
73
     * IDFC/Kotak, no-cost EMI is ICICI on 3 and 6 months but SBI on 3 only, and low-cost
74
     * is SBI. Stating one bank list for the badge would offer every bank every term.
75
     */
76
    @Test
77
    public void consolidatesFiveBadgesIntoOneWithBanksPerLine() {
78
        ModelOffer offer = model("Motorola",
79
                cashback("CC_EMI", "2500", "IDFC First Bank, Kotak Mahindra Bank", null, SEP_20),
80
                cashback("CC_FULL_SWIPE", "2000", "IDFC First Bank, State Bank of India", null, SEP_20),
81
                scheme("NCE 3, 6 months", "ICICI Bank"),
82
                scheme("NCE 3 month", "State Bank of India"),
83
                scheme("LCE 6, 9, 12, 18, 24 months", "State Bank of India"));
84
 
85
        String title = service.modelTitle(offer);
86
        assertEquals("SEPTEMBER 2026 Motorola Cashback Offer-2,500 On Credit Card EMI"
87
                + " & 2,000 On Credit Card Full Swipe", title);
88
 
89
        String detail = service.modelDetail(offer);
90
        assertTrue(detail, detail.contains("Rs.2,500 on Credit Card EMI with IDFC First Bank"));
91
        assertTrue(detail, detail.contains("NCE 3, 6 months with ICICI Bank"));
92
        assertTrue(detail, detail.contains("NCE 3 month with State Bank of India"));
93
        // no single trailing bank list, because no two lines share one
94
        assertTrue(detail, !detail.contains("Banks: "));
95
    }
96
 
97
    // ------------------------------------------------------------------ bank hoisting
98
 
99
    /** When every line shares one bank set it is stated once, not on each line. */
100
    @Test
101
    public void hoistsTheBankListWhenEveryLineSharesIt() {
102
        ModelOffer offer = model("Samsung",
103
                cashback("CC_FULL_SWIPE", "3000", "HDFC Bank, ICICI Bank", null, SEP_20),
104
                cashback("CC_EMI", "3000", "HDFC Bank, ICICI Bank", "LCE 3, 6 months", SEP_20));
105
 
106
        String detail = service.modelDetail(offer);
107
        assertTrue(detail, detail.endsWith("Banks: HDFC Bank, ICICI Bank"));
108
        assertTrue(detail, !detail.contains("with HDFC Bank"));
109
    }
110
 
111
    // ------------------------------------------------------------------ "Upto"
112
 
113
    /**
114
     * "Upto" only where a mode carries more than one value - which is what happens when
115
     * banks pay differently for the same thing. A single value is stated plainly, or the
116
     * badge would understate a firm offer.
117
     */
118
    @Test
119
    public void saysUptoOnlyWhenAModeHasSeveralValues() {
120
        assertTrue(service.modelTitle(model("Apple",
121
                cashback("CC_EMI", "6000", "Axis Bank", null, SEP_16),
122
                cashback("CC_EMI", "4000", "Axis Bank", null, SEP_26)))
123
                .contains("Upto 6,000 On Credit Card EMI"));
124
 
125
        String single = service.modelTitle(model("Apple",
126
                cashback("CC_EMI", "6000", "Axis Bank", null, SEP_26)));
127
        assertTrue(single, single.contains("6,000 On Credit Card EMI"));
128
        assertTrue(single, !single.contains("Upto"));
129
    }
130
 
131
    // ------------------------------------------------------------------ windows
132
 
133
    /**
134
     * Apple 1025780, Sep'26: Rs.6,000 to the 16th, then Rs.4,000 to the 26th - the same
135
     * banks and the same mode, stepping down.
136
     *
137
     * The badge spans 1-26 Sep, so the earlier amount MUST carry its own end date or the
138
     * badge advertises Rs.6,000 for ten days it is not available. The later amount runs to
139
     * the badge's own end and says nothing, which keeps the common case clean.
140
     */
141
    @Test
142
    public void anAmountThatEndsEarlyStatesItsOwnValidity() {
143
        ModelOffer offer = model("Apple",
144
                cashback("CC_EMI", "6000", "Axis Bank", null, SEP_16),
145
                cashback("CC_EMI", "4000", "Axis Bank", null, SEP_26));
146
 
147
        assertEquals(SEP_1, offer.start);
148
        assertEquals(SEP_26, offer.end);
149
 
150
        String detail = service.modelDetail(offer);
151
        assertTrue(detail, detail.contains("Rs.6,000 on Credit Card EMI (till 16 Sep)"));
152
        assertTrue(detail, detail.contains("Rs.4,000 on Credit Card EMI"));
153
        assertTrue(detail, !detail.contains("Rs.4,000 on Credit Card EMI (till"));
154
    }
155
 
156
    // ------------------------------------------------------------------ ordering
157
 
158
    /** Highest value first, so the number a partner is looking for leads. */
159
    @Test
160
    public void statesHigherValuesFirst() {
161
        String detail = service.modelDetail(model("Motorola",
162
                cashback("CC_EMI", "1500", "SBI", null, SEP_20),
163
                cashback("CC_EMI", "2500", "SBI", null, SEP_20)));
164
        assertTrue(detail, detail.indexOf("Rs.2,500") < detail.indexOf("Rs.1,500"));
165
    }
166
 
167
    // ------------------------------------------------------------------ scheme-only
168
 
169
    /** A model with no cashback at all is titled by its scheme, never "Cashback Offer". */
170
    @Test
171
    public void aSchemeOnlyModelIsTitledByItsScheme() {
172
        String title = service.modelTitle(model("Motorola",
173
                scheme("NCE 3, 6 months", "State Bank of India")));
174
        assertEquals("SEPTEMBER 2026 Motorola NCE 3, 6 months", title);
175
        assertTrue(title, !title.contains("Cashback Offer"));
176
        assertTrue(title, !title.contains("NA"));
177
    }
178
 
179
    // ------------------------------------------------------------------ tenure origin
180
 
181
    /**
182
     * A tenure belongs to the offer that granted it, never to the model.
183
     *
184
     * Edge 60 Pro's EMI cashback is IDFC/Kotak with NO tenure of its own, while its
185
     * schemes are ICICI's and SBI's. Attaching the model's tenures to that cashback would
186
     * promise no-cost EMI on a bank that never offered it.
187
     */
188
    @Test
189
    public void doesNotAttachAnotherOffersTenuresToACashback() {
190
        String detail = service.modelDetail(model("Motorola",
191
                cashback("CC_EMI", "2500", "IDFC First Bank", null, SEP_20),
192
                scheme("NCE 3, 6 months", "ICICI Bank")));
193
        assertTrue(detail, detail.contains("Rs.2,500 on Credit Card EMI with IDFC First Bank"));
194
        assertTrue(detail, !detail.contains("Credit Card EMI (NCE"));
195
    }
196
 
197
    // ------------------------------------------------------------------ length
198
 
199
    /** detailedText is VARCHAR(1024); a model with many lines must not overflow it. */
200
    @Test
201
    public void neverExceedsTheColumnWidth() {
202
        ModelOffer offer = new ModelOffer();
203
        offer.brand = "Samsung";
204
        for (int i = 0; i < 40; i++) {
205
            offer.add(cashback("CC_EMI", String.valueOf(1000 + i),
206
                    "HDFC Bank, ICICI Bank, State Bank of India, Axis Bank " + i, null, SEP_20));
207
        }
208
        assertTrue(service.modelDetail(offer).length() <= 1024);
209
        assertTrue(service.modelTitle(offer).length() <= 256);
210
    }
211
}