Subversion Repositories SmartDukaan

Rev

Rev 33916 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 33916 Rev 36960
Line 1... Line 1...
1
package com.spice.profitmandi.service.catalog;
1
package com.spice.profitmandi.service.catalog;
2
 
2
 
3
import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
3
import com.spice.profitmandi.common.exception.ProfitMandiBusinessException;
4
import com.spice.profitmandi.common.web.client.RestClient;
4
import com.spice.profitmandi.common.model.ComboCancellationResult;
-
 
5
import com.spice.profitmandi.common.model.ComboCancellationResult.ComboLinkedOrder;
5
import com.spice.profitmandi.dao.entity.catalog.*;
6
import com.spice.profitmandi.dao.entity.catalog.*;
6
import com.spice.profitmandi.dao.entity.fofo.FofoStore;
7
import com.spice.profitmandi.dao.entity.fofo.FofoStore;
-
 
8
import com.spice.profitmandi.dao.entity.transaction.Order;
-
 
9
import in.shop2020.model.v1.order.OrderStatus;
7
import com.spice.profitmandi.dao.model.UserCart;
10
import com.spice.profitmandi.dao.model.UserCart;
8
import com.spice.profitmandi.dao.repository.catalog.*;
11
import com.spice.profitmandi.dao.repository.catalog.*;
9
import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;
12
import com.spice.profitmandi.dao.repository.dtr.FofoStoreRepository;
-
 
13
import com.spice.profitmandi.dao.repository.transaction.OrderRepository;
10
import com.spice.profitmandi.dao.repository.user.CartLineRepository;
14
import com.spice.profitmandi.dao.repository.user.CartLineRepository;
11
import com.spice.profitmandi.dao.repository.user.UserRepository;
15
import com.spice.profitmandi.dao.repository.user.UserRepository;
12
import org.apache.logging.log4j.LogManager;
16
import org.apache.logging.log4j.LogManager;
13
import org.apache.logging.log4j.Logger;
17
import org.apache.logging.log4j.Logger;
14
import org.springframework.beans.factory.annotation.Autowired;
18
import org.springframework.beans.factory.annotation.Autowired;
Line 37... Line 41...
37
    @Autowired
41
    @Autowired
38
    ComboOptionRepository comboOptionRepository;
42
    ComboOptionRepository comboOptionRepository;
39
    @Autowired
43
    @Autowired
40
    ComboMappedModelRepository comboMappedModelRepository;
44
    ComboMappedModelRepository comboMappedModelRepository;
41
 
45
 
-
 
46
    @Autowired
-
 
47
    OrderRepository orderRepository;
-
 
48
 
42
    private static final Logger LOGGER = LogManager.getLogger(ComboServiceImpl.class);
49
    private static final Logger LOGGER = LogManager.getLogger(ComboServiceImpl.class);
43
 
50
 
44
    @Override
51
    @Override
45
    public boolean validateCombo(UserCart userCart) throws ProfitMandiBusinessException {
52
    public boolean validateCombo(UserCart userCart) throws ProfitMandiBusinessException {
46
        Map<Integer, Integer> itemQtyMap = cartLineRepository.selectAllByCart(userCart.getCartId()).stream().collect(Collectors.toMap(x -> x.getItemId(), x -> x.getQuantity()));
53
        Map<Integer, Integer> itemQtyMap = cartLineRepository.selectAllByCart(userCart.getCartId()).stream().collect(Collectors.toMap(x -> x.getItemId(), x -> x.getQuantity()));
Line 85... Line 92...
85
                throw new ProfitMandiBusinessException("FOC items cant be billed above Combo Qty", "FOC", "FOC items cant be billed above Combo Qty");
92
                throw new ProfitMandiBusinessException("FOC items cant be billed above Combo Qty", "FOC", "FOC items cant be billed above Combo Qty");
86
            }
93
            }
87
        }
94
        }
88
        return true;
95
        return true;
89
    }
96
    }
-
 
97
 
-
 
98
    // Combo cancellation rules (linkage resolved via the catalog combo definition, NOT just shared transaction):
-
 
99
    //   secondary is FOC      -> cancel main: auto-cancel the FOC (silent);  cancel FOC: standalone OK, main stays
-
 
100
    //   secondary is non-FOC  -> cancel main: standalone OK, secondary stays; cancel secondary: force-cancel main (confirm)
-
 
101
    @Override
-
 
102
    public ComboCancellationResult checkOrderCancellationForCombo(List<Order> orders) {
-
 
103
        ComboCancellationResult result = ComboCancellationResult.noCombo();
-
 
104
        if (orders == null || orders.isEmpty()) {
-
 
105
            return result;
-
 
106
        }
-
 
107
 
-
 
108
        Set<Integer> cancelledIds = orders.stream().map(Order::getId).collect(Collectors.toSet());
-
 
109
 
-
 
110
        Map<Integer, List<Order>> cancelledByTransaction = orders.stream()
-
 
111
                .filter(o -> o.getTransactionId() != null)
-
 
112
                .collect(Collectors.groupingBy(Order::getTransactionId));
-
 
113
 
-
 
114
        Set<Integer> autoCancelFocIds = new HashSet<>();
-
 
115
        Set<Integer> linkedMainIds = new HashSet<>();
-
 
116
 
-
 
117
        for (Map.Entry<Integer, List<Order>> entry : cancelledByTransaction.entrySet()) {
-
 
118
            List<Order> cancelledInTransaction = entry.getValue();
-
 
119
            List<Order> siblings = orderRepository.selectAllByTransactionId(entry.getKey());
-
 
120
            if (siblings == null || siblings.isEmpty()) {
-
 
121
                continue;
-
 
122
            }
-
 
123
 
-
 
124
            Integer warehouseId = resolveWarehouseId(siblings);
-
 
125
            if (warehouseId == null) {
-
 
126
                continue;
-
 
127
            }
-
 
128
 
-
 
129
            Map<Integer, Integer> orderIdToCatalogId = resolveOrderCatalogIds(siblings);
-
 
130
 
-
 
131
            // main-catalog -> secondary-catalogs, from the combo definition for this warehouse
-
 
132
            Map<Integer, Set<Integer>> mainToSecondaries =
-
 
133
                    buildComboCatalogMap(new ArrayList<>(new HashSet<>(orderIdToCatalogId.values())), warehouseId);
-
 
134
            if (mainToSecondaries.isEmpty()) {
-
 
135
                continue;
-
 
136
            }
-
 
137
 
-
 
138
            // inverse: secondary-catalog -> main-catalogs
-
 
139
            Map<Integer, Set<Integer>> secondaryToMains = new HashMap<>();
-
 
140
            for (Map.Entry<Integer, Set<Integer>> e : mainToSecondaries.entrySet()) {
-
 
141
                for (Integer secondaryCatalog : e.getValue()) {
-
 
142
                    secondaryToMains.computeIfAbsent(secondaryCatalog, k -> new HashSet<>()).add(e.getKey());
-
 
143
                }
-
 
144
            }
-
 
145
 
-
 
146
            // siblings indexed by their catalog id
-
 
147
            Map<Integer, List<Order>> siblingsByCatalog = new HashMap<>();
-
 
148
            for (Order sibling : siblings) {
-
 
149
                Integer catalogId = orderIdToCatalogId.get(sibling.getId());
-
 
150
                if (catalogId != null) {
-
 
151
                    siblingsByCatalog.computeIfAbsent(catalogId, k -> new ArrayList<>()).add(sibling);
-
 
152
                }
-
 
153
            }
-
 
154
 
-
 
155
            // mains that will be cancelled = user-selected mains + mains forced by a non-FOC secondary cancel
-
 
156
            Set<Integer> mainOrderIdsToCancel = new HashSet<>();
-
 
157
            for (Order cancelled : cancelledInTransaction) {
-
 
158
                Integer catalogId = orderIdToCatalogId.get(cancelled.getId());
-
 
159
                if (catalogId != null && mainToSecondaries.containsKey(catalogId)) {
-
 
160
                    mainOrderIdsToCancel.add(cancelled.getId());
-
 
161
                }
-
 
162
            }
-
 
163
 
-
 
164
            // Pass 1: a non-FOC secondary being cancelled mandatorily cancels its main(s) -> ask for confirmation
-
 
165
            for (Order cancelled : cancelledInTransaction) {
-
 
166
                Integer catalogId = orderIdToCatalogId.get(cancelled.getId());
-
 
167
                if (catalogId == null || !secondaryToMains.containsKey(catalogId) || isFoc(cancelled)) {
-
 
168
                    continue;
-
 
169
                }
-
 
170
                for (Integer mainCatalog : secondaryToMains.get(catalogId)) {
-
 
171
                    for (Order mainOrder : siblingsByCatalog.getOrDefault(mainCatalog, Collections.emptyList())) {
-
 
172
                        if (cancelledIds.contains(mainOrder.getId())
-
 
173
                                || !OrderStatus.SUBMITTED_FOR_PROCESSING.equals(mainOrder.getStatus())) {
-
 
174
                            continue;
-
 
175
                        }
-
 
176
                        mainOrderIdsToCancel.add(mainOrder.getId());
-
 
177
                        if (linkedMainIds.add(mainOrder.getId())) {
-
 
178
                            result.setConfirmationRequired(true);
-
 
179
                            result.getLinkedMainOrders().add(new ComboLinkedOrder(
-
 
180
                                    mainOrder.getId(),
-
 
181
                                    mainOrder.getLineItem().getBrand() + " " + mainOrder.getLineItem().getModelName() + " " + mainOrder.getLineItem().getModelNumber(),
-
 
182
                                    mainOrder.getLineItem().getQuantity()
-
 
183
                            ));
-
 
184
                        }
-
 
185
                    }
-
 
186
                }
-
 
187
            }
-
 
188
 
-
 
189
            // Pass 2: every main being cancelled auto-cancels its FOC secondaries (the free gift follows the main)
-
 
190
            for (Integer mainOrderId : mainOrderIdsToCancel) {
-
 
191
                Integer mainCatalog = orderIdToCatalogId.get(mainOrderId);
-
 
192
                if (mainCatalog == null) {
-
 
193
                    continue;
-
 
194
                }
-
 
195
                for (Integer secondaryCatalog : mainToSecondaries.getOrDefault(mainCatalog, Collections.emptySet())) {
-
 
196
                    for (Order secondary : siblingsByCatalog.getOrDefault(secondaryCatalog, Collections.emptyList())) {
-
 
197
                        if (!cancelledIds.contains(secondary.getId())
-
 
198
                                && OrderStatus.SUBMITTED_FOR_PROCESSING.equals(secondary.getStatus())
-
 
199
                                && isFoc(secondary)) {
-
 
200
                            autoCancelFocIds.add(secondary.getId());
-
 
201
                        }
-
 
202
                    }
-
 
203
                }
-
 
204
            }
-
 
205
        }
-
 
206
 
-
 
207
        result.getAutoCancelFocOrderIds().addAll(autoCancelFocIds);
-
 
208
        return result;
-
 
209
    }
-
 
210
 
-
 
211
    private boolean isFoc(Order order) {
-
 
212
        return order.getLineItem() != null && "FOC".equals(order.getLineItem().getBrand());
-
 
213
    }
-
 
214
 
-
 
215
    private Integer resolveWarehouseId(List<Order> siblings) {
-
 
216
        for (Order order : siblings) {
-
 
217
            if (order.getRetailerId() == null) {
-
 
218
                continue;
-
 
219
            }
-
 
220
            try {
-
 
221
                FofoStore store = fofoStoreRepository.selectByRetailerId(order.getRetailerId());
-
 
222
                if (store != null) {
-
 
223
                    return store.getWarehouseId();
-
 
224
                }
-
 
225
            } catch (Exception e) {
-
 
226
                LOGGER.warn("Combo cancel: unable to resolve warehouse for retailer {} - {}", order.getRetailerId(), e.getMessage());
-
 
227
            }
-
 
228
        }
-
 
229
        return null;
-
 
230
    }
-
 
231
 
-
 
232
    private Map<Integer, Integer> resolveOrderCatalogIds(List<Order> siblings) {
-
 
233
        Set<Integer> itemIds = siblings.stream()
-
 
234
                .filter(o -> o.getLineItem() != null && o.getLineItem().getItemId() != null)
-
 
235
                .map(o -> o.getLineItem().getItemId())
-
 
236
                .collect(Collectors.toSet());
-
 
237
 
-
 
238
        Map<Integer, Integer> itemIdToCatalogId = new HashMap<>();
-
 
239
        if (!itemIds.isEmpty()) {
-
 
240
            try {
-
 
241
                for (Item item : itemRepository.selectByIds(itemIds)) {
-
 
242
                    itemIdToCatalogId.put(item.getId(), item.getCatalogItemId());
-
 
243
                }
-
 
244
            } catch (Exception e) {
-
 
245
                LOGGER.warn("Combo cancel: unable to resolve items - {}", e.getMessage());
-
 
246
            }
-
 
247
        }
-
 
248
 
-
 
249
        Map<Integer, Integer> orderIdToCatalogId = new HashMap<>();
-
 
250
        for (Order order : siblings) {
-
 
251
            if (order.getLineItem() == null || order.getLineItem().getItemId() == null) {
-
 
252
                continue;
-
 
253
            }
-
 
254
            Integer catalogId = itemIdToCatalogId.get(order.getLineItem().getItemId());
-
 
255
            if (catalogId != null) {
-
 
256
                orderIdToCatalogId.put(order.getId(), catalogId);
-
 
257
            }
-
 
258
        }
-
 
259
        return orderIdToCatalogId;
-
 
260
    }
-
 
261
 
-
 
262
    private Map<Integer, Set<Integer>> buildComboCatalogMap(List<Integer> catalogIds, int warehouseId) {
-
 
263
        Map<Integer, Set<Integer>> mainToSecondaries = new HashMap<>();
-
 
264
        if (catalogIds.isEmpty()) {
-
 
265
            return mainToSecondaries;
-
 
266
        }
-
 
267
        List<ComboModel> comboModels = comboModelRepository.selectByCatalogIdsAndWarehouseId(catalogIds, warehouseId);
-
 
268
        for (ComboModel comboModel : comboModels) {
-
 
269
            for (ComboOption comboOption : comboOptionRepository.selectByComboId(comboModel.getId())) {
-
 
270
                for (ComboMappedModel mappedModel : comboMappedModelRepository.selectByComboOptionId(comboOption.getId())) {
-
 
271
                    mainToSecondaries
-
 
272
                            .computeIfAbsent(comboModel.getCatalogId(), k -> new HashSet<>())
-
 
273
                            .add(mappedModel.getComboCatalogId());
-
 
274
                }
-
 
275
            }
-
 
276
        }
-
 
277
        return mainToSecondaries;
-
 
278
    }
90
}
279
}