Subversion Repositories SmartDukaan

Rev

Rev 36716 | Rev 36728 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 36716 Rev 36727
Line 497... Line 497...
497
	@GetMapping(value = "/beatPlan/migrateStoreLatLng")
497
	@GetMapping(value = "/beatPlan/migrateStoreLatLng")
498
	public ResponseEntity<?> migrateStoreLatLng(
498
	public ResponseEntity<?> migrateStoreLatLng(
499
			@RequestParam(required = false, defaultValue = "false") boolean apply,
499
			@RequestParam(required = false, defaultValue = "false") boolean apply,
500
			@RequestParam(required = false, defaultValue = "5") double thresholdKm,
500
			@RequestParam(required = false, defaultValue = "5") double thresholdKm,
501
			@RequestParam(required = false, defaultValue = "0") int limit,
501
			@RequestParam(required = false, defaultValue = "0") int limit,
-
 
502
			@RequestParam(required = false, defaultValue = "0") int offset,
502
			@RequestParam(required = false, defaultValue = "0") int offset) throws ProfitMandiBusinessException {
503
			@RequestParam(required = false, defaultValue = "40") int maxSeconds) throws ProfitMandiBusinessException {
503
 
504
 
504
		List<FofoStore> all = fofoStoreRepository.selectActiveStores();
505
		List<FofoStore> all = fofoStoreRepository.selectActiveStores();
505
		int totalAvailable = all.size();
506
		int totalAvailable = all.size();
506
		// offset + limit so this can be run in batches against large datasets
-
 
507
		int from = Math.max(0, Math.min(offset, totalAvailable));
507
		int from = Math.max(0, Math.min(offset, totalAvailable));
508
		int to = limit > 0 ? Math.min(from + limit, totalAvailable) : totalAvailable;
-
 
509
		List<FofoStore> stores = all.subList(from, to);
-
 
510
 
508
 
-
 
509
		// Hard cap (if limit given), else go to the end of the list.
-
 
510
		int hardTo = limit > 0 ? Math.min(from + limit, totalAvailable) : totalAvailable;
-
 
511
 
-
 
512
		// Time budget: stop processing once we approach the gateway timeout and
-
 
513
		// return nextOffset so the caller can resume. Geocoding is the slow part
-
 
514
		// (network/cache), so a fixed batch size could still time out on a cache-miss
-
 
515
		// run — a wall-clock budget is safer. maxSeconds defaults to 40 (< typical 60s gateway).
-
 
516
		long deadlineMs = System.currentTimeMillis() + Math.max(5, maxSeconds) * 1000L;
-
 
517
 
-
 
518
		List<FofoStore> stores = all.subList(from, hardTo);
511
		List<Integer> ids = stores.stream().map(FofoStore::getId).collect(Collectors.toList());
519
		List<Integer> ids = stores.stream().map(FofoStore::getId).collect(Collectors.toList());
512
		Map<Integer, CustomRetailer> retailerMap = retailerService.getFofoRetailers(ids);
520
		Map<Integer, CustomRetailer> retailerMap = retailerService.getFofoRetailers(ids);
513
 
521
 
514
		int total = stores.size();
522
		int total = 0;            // stores actually processed this call
515
		int updated = 0, kept = 0, noAddress = 0, noGeocode = 0, errored = 0;
523
		int updated = 0, kept = 0, noAddress = 0, noGeocode = 0, errored = 0;
-
 
524
		boolean stoppedOnTime = false;
-
 
525
		int nextIndex = from;     // absolute index of next unprocessed store
516
		List<Map<String, Object>> changes = new ArrayList<>();
526
		List<Map<String, Object>> changes = new ArrayList<>();
517
 
527
 
518
		for (FofoStore store : stores) {
528
		for (FofoStore store : stores) {
-
 
529
			// Stop before doing more slow geocoding work if we've spent our budget.
-
 
530
			if (System.currentTimeMillis() >= deadlineMs) {
-
 
531
				stoppedOnTime = true;
-
 
532
				break;
-
 
533
			}
-
 
534
			total++;
-
 
535
			nextIndex++;
519
			try {
536
			try {
520
				CustomRetailer retailer = retailerMap.get(store.getId());
537
				CustomRetailer retailer = retailerMap.get(store.getId());
521
				if (retailer == null || retailer.getAddress() == null) {
538
				if (retailer == null || retailer.getAddress() == null) {
522
					noAddress++;
539
					noAddress++;
523
					continue;
540
					continue;
Line 556... Line 573...
556
 
573
 
557
				if (shouldUpdate) {
574
				if (shouldUpdate) {
558
					if (apply) {
575
					if (apply) {
559
						store.setLatitude(String.valueOf(coords[0]));
576
						store.setLatitude(String.valueOf(coords[0]));
560
						store.setLongitude(String.valueOf(coords[1]));
577
						store.setLongitude(String.valueOf(coords[1]));
-
 
578
						store.setLatLngUpdatedTimestamp(LocalDateTime.now());
561
						fofoStoreRepository.persist(store);
579
						fofoStoreRepository.persist(store);
562
					}
580
					}
563
					updated++;
581
					updated++;
564
					Map<String, Object> ch = new HashMap<>();
582
					Map<String, Object> ch = new HashMap<>();
565
					ch.put("storeId", store.getId());
583
					ch.put("storeId", store.getId());
Line 570... Line 588...
570
					ch.put("newLng", coords[1]);
588
					ch.put("newLng", coords[1]);
571
					ch.put("distKm", distKm >= 0 ? Math.round(distKm * 10.0) / 10.0 : null);
589
					ch.put("distKm", distKm >= 0 ? Math.round(distKm * 10.0) / 10.0 : null);
572
					ch.put("reason", reason);
590
					ch.put("reason", reason);
573
					changes.add(ch);
591
					changes.add(ch);
574
				} else {
592
				} else {
-
 
593
					// Verified-kept: lat/lng was already within threshold. Still stamp it
-
 
594
					// so "processed vs pending" can be told from lat_lng_updated_timestamp.
-
 
595
					if (apply) {
-
 
596
						store.setLatLngUpdatedTimestamp(LocalDateTime.now());
-
 
597
						fofoStoreRepository.persist(store);
-
 
598
					}
575
					kept++;
599
					kept++;
576
				}
600
				}
577
			} catch (Exception e) {
601
			} catch (Exception e) {
578
				errored++;
602
				errored++;
579
				LOGGER.warn("Geocode/migrate failed for fofoId={}: {}", store.getId(), e.getMessage());
603
				LOGGER.warn("Geocode/migrate failed for fofoId={}: {}", store.getId(), e.getMessage());
Line 581... Line 605...
581
		}
605
		}
582
 
606
 
583
		Map<String, Object> result = new HashMap<>();
607
		Map<String, Object> result = new HashMap<>();
584
		result.put("mode", apply ? "APPLIED" : "DRY RUN — pass &apply=true to actually update");
608
		result.put("mode", apply ? "APPLIED" : "DRY RUN — pass &apply=true to actually update");
585
		result.put("thresholdKm", thresholdKm);
609
		result.put("thresholdKm", thresholdKm);
586
		result.put("totalAvailable", totalAvailable);  // total active stores in DB
610
		result.put("totalAvailable", totalAvailable);   // total active stores in DB
587
		result.put("offset", from);
611
		result.put("offset", from);
588
		result.put("processed", total);                 // stores processed this run
612
		result.put("processed", total);                  // stores processed this call
589
		result.put("nextOffset", to);                   // next offset to resume (or = totalAvailable when done)
613
		result.put("nextOffset", nextIndex);             // resume here next call
590
		result.put("done", to >= totalAvailable);
614
		result.put("done", nextIndex >= totalAvailable); // true when nothing left
-
 
615
		result.put("stoppedOnTimeBudget", stoppedOnTime);// true if we paused for time, not because we finished
591
		result.put("updated", updated);
616
		result.put("updated", updated);
592
		result.put("kept", kept);
617
		result.put("kept", kept);
593
		result.put("noAddress", noAddress);
618
		result.put("noAddress", noAddress);
594
		result.put("noGeocode", noGeocode);
619
		result.put("noGeocode", noGeocode);
595
		result.put("errored", errored);
620
		result.put("errored", errored);