Subversion Repositories SmartDukaan

Rev

Rev 36306 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
36306 amit 1
package com.smartdukaan.cron.scheduled;
2
 
3
import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
4
import com.spice.profitmandi.dao.entity.transaction.CronBatch;
5
import com.spice.profitmandi.dao.enumuration.catalog.OfferSchemeType;
6
import com.spice.profitmandi.dao.model.CreateOfferRequest;
36338 amit 7
import com.spice.profitmandi.service.cron.CronBatchService;
36306 amit 8
import com.spice.profitmandi.service.offers.OfferPartnerPayoutData;
36338 amit 9
import com.spice.profitmandi.service.offers.OfferProcessingHelper;
36306 amit 10
import com.spice.profitmandi.service.offers.OfferService;
11
import com.spice.profitmandi.service.offers.SellinPartnerPayoutData;
12
import com.spice.profitmandi.service.transaction.PartnerLimitUpdateData;
13
import org.apache.logging.log4j.LogManager;
14
import org.apache.logging.log4j.Logger;
15
import org.springframework.beans.factory.annotation.Autowired;
16
import org.springframework.stereotype.Component;
17
 
18
import java.util.LinkedHashMap;
19
import java.util.List;
20
 
21
/**
22
 * Batch-aware scheduled tasks with per-partner transaction isolation.
23
 * NO @Transactional at class level — each partner gets its own transaction
24
 * via REQUIRES_NEW in the helper beans.
25
 *
26
 * Tracks every run in cron_batch / cron_batch_item tables.
27
 * Sends failure summary email to technology on partial failures.
28
 */
29
@Component
30
public class BatchScheduledTasks {
31
 
32
    private static final Logger LOGGER = LogManager.getLogger(BatchScheduledTasks.class);
33
 
34
    @Autowired
35
    private CronBatchService cronBatchService;
36
 
37
    @Autowired
38
    private OfferProcessingHelper offerProcessingHelper;
39
 
40
    @Autowired
41
    private OfferService offerService;
42
 
43
    @Autowired
44
    private PartnerLimitHelper partnerLimitHelper;
45
 
46
    /**
47
     * Processes a single offer with per-partner transaction isolation and batch tracking.
48
     * Routes to activation or sellin based on scheme type.
49
     *
50
     * Flow:
51
     * 1. Load offer (read-only transaction)
52
     * 2. Calculate payouts per partner (read-only transaction)
53
     * 3. Create batch record with all eligible partners
54
     * 4. Per-partner: call helper with REQUIRES_NEW — commits/rolls back independently
55
     * 5. Finalize batch: update counts, send failure email if any
56
     */
57
    public void processOfferWithBatch(int offerId) throws Exception {
58
        CreateOfferRequest createOfferRequest = offerProcessingHelper.loadOfferRequest(offerId);
59
        if (createOfferRequest == null) {
60
            return;
61
        }
62
        LOGGER.info("Processing offer {} (type={}) with batch tracking", offerId, createOfferRequest.getSchemeType());
63
 
64
        if (createOfferRequest.getSchemeType().equals(OfferSchemeType.ACTIVATION)) {
65
            processActivationOfferWithBatch(offerId, createOfferRequest);
66
        } else if (createOfferRequest.getSchemeType().equals(OfferSchemeType.SELLIN)) {
67
            processSellinOfferWithBatch(offerId, createOfferRequest);
68
        } else {
69
            LOGGER.warn("Offer {} has unsupported scheme type: {}", offerId, createOfferRequest.getSchemeType());
70
        }
71
    }
72
 
73
    private void processActivationOfferWithBatch(int offerId, CreateOfferRequest createOfferRequest) throws Exception {
74
        List<OfferPartnerPayoutData> partnerPayouts;
75
        try {
76
            partnerPayouts = offerService.calculateOfferPayouts(createOfferRequest);
77
        } catch (Exception e) {
78
            LOGGER.error("Failed to calculate activation payouts for offer {}: {}", offerId, e.getMessage());
79
            return;
80
        }
81
 
82
        if (partnerPayouts.isEmpty()) {
83
            LOGGER.info("No eligible partners for activation offer {}", offerId);
84
            return;
85
        }
86
 
87
        LinkedHashMap<Integer, String> fofoIdPartnerNameMap = new LinkedHashMap<>();
88
        for (OfferPartnerPayoutData data : partnerPayouts) {
89
            fofoIdPartnerNameMap.put(data.getFofoId(), "fofo-" + data.getFofoId());
90
        }
91
 
92
        CronBatch batch = cronBatchService.createBatch("processActivationOffer-" + offerId, fofoIdPartnerNameMap);
93
 
94
        for (OfferPartnerPayoutData data : partnerPayouts) {
95
            try {
96
                offerProcessingHelper.processPartnerOfferPayout(
97
                        batch.getId(), data.getFofoId(), offerId, createOfferRequest.getDescription(),
98
                        data.getLineItemValueMap(), data.getItemCriteriaPayout(), data.getCriteriaId(),
99
                        data.getSerialNumberPaid(), data.getAgeingSummaryModelsMap(),
100
                        data.getEligiblePayoutValue(), data.isDiscount());
101
            } catch (Exception e) {
102
                LOGGER.error("Activation offer {} failed for fofoId={}: {}", offerId, data.getFofoId(), e.getMessage());
103
                cronBatchService.markItemFailed(batch.getId(), data.getFofoId(), e.getMessage());
104
            }
105
        }
106
 
107
        cronBatchService.finalizeBatch(batch.getId());
108
    }
109
 
110
    private void processSellinOfferWithBatch(int offerId, CreateOfferRequest createOfferRequest) throws Exception {
111
        List<SellinPartnerPayoutData> partnerPayouts;
112
        try {
113
            partnerPayouts = offerService.calculateSellinPayouts(createOfferRequest);
114
        } catch (Exception e) {
115
            LOGGER.error("Failed to calculate sellin payouts for offer {}: {}", offerId, e.getMessage());
116
            return;
117
        }
118
 
119
        if (partnerPayouts.isEmpty()) {
120
            LOGGER.info("No eligible partners for sellin offer {}", offerId);
121
            return;
122
        }
123
 
124
        LinkedHashMap<Integer, String> fofoIdPartnerNameMap = new LinkedHashMap<>();
125
        for (SellinPartnerPayoutData data : partnerPayouts) {
126
            fofoIdPartnerNameMap.put(data.getFofoId(), "fofo-" + data.getFofoId());
127
        }
128
 
129
        CronBatch batch = cronBatchService.createBatch("processSellinOffer-" + offerId, fofoIdPartnerNameMap);
130
 
131
        for (SellinPartnerPayoutData data : partnerPayouts) {
132
            try {
133
                offerProcessingHelper.processPartnerSellinPayout(
134
                        batch.getId(), data.getFofoId(), offerId, createOfferRequest.getDescription(),
135
                        data.getSerialNumberInventoryItemMap(), data.getItemCriteriaPayout(), data.getCriteriaId(),
136
                        data.getSerialNumberPaid(), data.getEligiblePayoutValue(), data.isDiscount());
137
            } catch (Exception e) {
138
                LOGGER.error("Sellin offer {} failed for fofoId={}: {}", offerId, data.getFofoId(), e.getMessage());
139
                cronBatchService.markItemFailed(batch.getId(), data.getFofoId(), e.getMessage());
140
            }
141
        }
142
 
143
        cronBatchService.finalizeBatch(batch.getId());
144
    }
145
 
146
    /**
147
     * Recalculates partner credit limits. Only writes to partners where values actually changed.
148
     *
149
     * Flow:
150
     * 1. Read phase: calculate limits for all 1,500 partners, compare with current values
151
     * 2. Create batch with only changed partners (~50-100 typically)
152
     * 3. Per-partner: update in REQUIRES_NEW transaction
153
     * 4. Finalize: counts + failure email
154
     */
155
    public void updatePartnerLimitWithBatch() throws Exception {
156
        List<PartnerLimitUpdateData> changedPartners;
157
        try {
158
            changedPartners = partnerLimitHelper.calculateChangedPartnerLimits();
159
        } catch (Exception e) {
160
            LOGGER.error("Failed to calculate partner limits: {}", e.getMessage());
161
            return;
162
        }
163
 
164
        if (changedPartners.isEmpty()) {
165
            LOGGER.info("No partner limits changed, skipping");
166
            return;
167
        }
168
 
169
        LinkedHashMap<Integer, String> fofoIdPartnerNameMap = new LinkedHashMap<>();
170
        for (PartnerLimitUpdateData data : changedPartners) {
171
            fofoIdPartnerNameMap.put(data.getFofoId(), "fofo-" + data.getFofoId());
172
        }
173
 
174
        CronBatch batch = cronBatchService.createBatch("updatePartnerLimit", fofoIdPartnerNameMap);
175
 
176
        for (PartnerLimitUpdateData data : changedPartners) {
177
            try {
178
                partnerLimitHelper.updateSinglePartnerLimit(batch.getId(), data);
179
            } catch (Exception e) {
180
                LOGGER.error("updatePartnerLimit failed for fofoId={}: {}", data.getFofoId(), e.getMessage());
181
                cronBatchService.markItemFailed(batch.getId(), data.getFofoId(), e.getMessage());
182
            }
183
        }
184
 
185
        cronBatchService.finalizeBatch(batch.getId());
186
    }
187
}