Subversion Repositories SmartDukaan

Rev

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

Rev 37828 Rev 37831
Line 241... Line 241...
241
                            + " of " + qty + " free in the source's vendor warehouses");
241
                            + " of " + qty + " free in the source's vendor warehouses");
242
                    continue;
242
                    continue;
243
                }
243
                }
244
            }
244
            }
245
 
245
 
-
 
246
            // The order is priced from one cost layer; only units received at that price (or with no cost recorded,
-
 
247
            // which is what a catalog-priced line moves) may fill it, so the layers left behind stay true.
-
 
248
            Float price = order.getLineItem().getUnitPrice();
246
            for (Map.Entry<Integer, Integer> chunk : chunks.entrySet()) {
249
            for (Map.Entry<Integer, Integer> chunk : chunks.entrySet()) {
247
                Line line = new Line();
250
                Line line = new Line();
248
                line.orderId = order.getId();
251
                line.orderId = order.getId();
249
                line.itemId = itemId;
252
                line.itemId = itemId;
250
                line.item = description;
253
                line.item = description;
251
                line.qty = chunk.getValue();
254
                line.qty = chunk.getValue();
252
                line.fromWarehouseId = chunk.getKey();
255
                line.fromWarehouseId = chunk.getKey();
253
                line.repoint = repoint;
256
                line.repoint = repoint;
254
                line.serialized = serialized;
257
                line.serialized = serialized;
255
                String poolKey = key(chunk.getKey(), itemId);
258
                String poolKey = key(chunk.getKey(), itemId) + "@" + price;
256
                if (serialized) {
259
                if (serialized) {
257
                    List<String> pool = serialPools.computeIfAbsent(poolKey, x -> this.billableImeis(itemId, chunk.getKey()));
260
                    List<String> pool = serialPools.computeIfAbsent(poolKey, x -> this.billableImeis(itemId, chunk.getKey(), price));
258
                    if (pool.size() < line.qty) {
261
                    if (pool.size() < line.qty) {
259
                        plan.problems.add("order " + order.getId() + " " + description + ": " + pool.size()
262
                        plan.problems.add("order " + order.getId() + " " + description + ": " + pool.size()
260
                                + " billable IMEI(s) in warehouse " + chunk.getKey() + ", needs " + line.qty);
263
                                + " billable IMEI(s) at " + price + " in warehouse " + chunk.getKey() + ", needs " + line.qty);
261
                        continue;
264
                        continue;
262
                    }
265
                    }
263
                    line.imeis.addAll(pool.subList(0, line.qty));
266
                    line.imeis.addAll(pool.subList(0, line.qty));
264
                    pool.subList(0, line.qty).clear();
267
                    pool.subList(0, line.qty).clear();
265
                } else {
268
                } else {
266
                    int lots = lotPools.computeIfAbsent(poolKey, x -> this.billableLotQuantity(itemId, chunk.getKey()));
269
                    int lots = lotPools.computeIfAbsent(poolKey, x -> this.billableLotQuantity(itemId, chunk.getKey(), price));
267
                    if (lots < line.qty) {
270
                    if (lots < line.qty) {
268
                        plan.problems.add("order " + order.getId() + " " + description + ": " + lots
271
                        plan.problems.add("order " + order.getId() + " " + description + ": " + lots
269
                                + " billable unit(s) in warehouse " + chunk.getKey() + ", needs " + line.qty);
272
                                + " billable unit(s) at " + price + " in warehouse " + chunk.getKey() + ", needs " + line.qty);
270
                        continue;
273
                        continue;
271
                    }
274
                    }
272
                    lotPools.put(poolKey, lots - line.qty);
275
                    lotPools.put(poolKey, lots - line.qty);
273
                }
276
                }
274
                plan.lines.add(line);
277
                plan.lines.add(line);
Line 280... Line 283...
280
        }
283
        }
281
        return plan;
284
        return plan;
282
    }
285
    }
283
 
286
 
284
    // Billing takes an IMEI only at quantity 1 with a last scan that leaves it in stock (WarehouseServiceImpl billing).
287
    // Billing takes an IMEI only at quantity 1 with a last scan that leaves it in stock (WarehouseServiceImpl billing).
-
 
288
    // Only units at the billed price, then those with no cost recorded - core billing ranks lots the same way.
285
    private List<String> billableImeis(int itemId, int vendorWarehouseId) {
289
    private List<String> billableImeis(int itemId, int vendorWarehouseId, Float price) {
286
        return warehouseInventoryItemRepository.selectBillableStock(itemId, vendorWarehouseId).stream()
290
        return warehouseInventoryItemRepository.selectBillableStock(itemId, vendorWarehouseId).stream()
287
                .filter(x -> x.getCurrentQuantity() == 1 && x.getSerialNumber() != null && !x.getSerialNumber().trim().isEmpty())
291
                .filter(x -> x.getCurrentQuantity() == 1 && x.getSerialNumber() != null && !x.getSerialNumber().trim().isEmpty())
288
                .filter(x -> WarehouseServiceImpl.GOOD_SCAN_TYPES.contains(x.getLastScanType()))
292
                .filter(x -> WarehouseServiceImpl.GOOD_SCAN_TYPES.contains(x.getLastScanType()))
-
 
293
                .filter(x -> WarehouseServiceImpl.costRank(x.getReceiptUnitCost(), price) < 2)
-
 
294
                .sorted(Comparator.comparingInt((WarehouseInventoryItem x) -> WarehouseServiceImpl.costRank(x.getReceiptUnitCost(), price))
289
                .sorted(Comparator.comparing(WarehouseInventoryItem::getCreated, Comparator.nullsFirst(Comparator.naturalOrder())))
295
                        .thenComparing(WarehouseInventoryItem::getCreated, Comparator.nullsFirst(Comparator.naturalOrder())))
290
                .map(WarehouseInventoryItem::getSerialNumber)
296
                .map(WarehouseInventoryItem::getSerialNumber)
291
                .collect(Collectors.toCollection(ArrayList::new));
297
                .collect(Collectors.toCollection(ArrayList::new));
292
    }
298
    }
293
 
299
 
294
    private int billableLotQuantity(int itemId, int vendorWarehouseId) {
300
    private int billableLotQuantity(int itemId, int vendorWarehouseId, Float price) {
295
        return warehouseInventoryItemRepository.selectBillableStock(itemId, vendorWarehouseId).stream()
301
        return warehouseInventoryItemRepository.selectBillableStock(itemId, vendorWarehouseId).stream()
296
                .filter(x -> x.getCurrentQuantity() > 0)
302
                .filter(x -> x.getCurrentQuantity() > 0)
-
 
303
                .filter(x -> WarehouseServiceImpl.costRank(x.getReceiptUnitCost(), price) < 2)
297
                .mapToInt(WarehouseInventoryItem::getCurrentQuantity).sum();
304
                .mapToInt(WarehouseInventoryItem::getCurrentQuantity).sum();
298
    }
305
    }
299
 
306
 
300
    // A vendor warehouse the source bills from: its own OURS/GOOD stock, not the Dummy phantom target.
307
    // A vendor warehouse the source bills from: its own OURS/GOOD stock, not the Dummy phantom target.
301
    private boolean isRealVendorWarehouse(Integer warehouseId, int sourceWarehouseId, Map<Integer, InventoryWarehouse> cache) {
308
    private boolean isRealVendorWarehouse(Integer warehouseId, int sourceWarehouseId, Map<Integer, InventoryWarehouse> cache) {