Subversion Repositories SmartDukaan

Rev

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

Rev 36660 Rev 36663
Line 93... Line 93...
93
 
93
 
94
	@Autowired
94
	@Autowired
95
	private com.spice.profitmandi.dao.repository.dtr.LeadLiveLocationRepository leadLiveLocationRepositoryAuto;
95
	private com.spice.profitmandi.dao.repository.dtr.LeadLiveLocationRepository leadLiveLocationRepositoryAuto;
96
	@Autowired
96
	@Autowired
97
	private com.spice.profitmandi.dao.repository.dtr.LeadActivityRepository leadActivityRepositoryAuto;
97
	private com.spice.profitmandi.dao.repository.dtr.LeadActivityRepository leadActivityRepositoryAuto;
-
 
98
	@Autowired
-
 
99
	private com.spice.profitmandi.dao.repository.dtr.UserRepository userRepositoryAuto;
-
 
100
	@Autowired
-
 
101
	private com.spice.profitmandi.common.web.client.RestClient restClientAuto;
-
 
102
	@Autowired
-
 
103
	private com.spice.profitmandi.dao.repository.auth.LocationTrackingRepository locationTrackingRepositoryAuto;
98
 
104
 
99
	private static Double parseDoubleOrNull(String s) {
105
	private static Double parseDoubleOrNull(String s) {
100
		if (s == null || s.trim().isEmpty()) return null;
106
		if (s == null || s.trim().isEmpty()) return null;
101
		try {
107
		try {
102
			return Double.parseDouble(s.trim());
108
			return Double.parseDouble(s.trim());
Line 114... Line 120...
114
				* Math.sin(dLng / 2) * Math.sin(dLng / 2);
120
				* Math.sin(dLng / 2) * Math.sin(dLng / 2);
115
		double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
121
		double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
116
		return R * c;
122
		return R * c;
117
	}
123
	}
118
 
124
 
-
 
125
	// ====================== ASSIGN VISIT ======================
-
 
126
	// Day View "Assign Visit" — lets an admin pick parties (stores) for a specific
-
 
127
	// auth user on a specific date and pushes them as visit tasks to the v2
-
 
128
	// /profitmandi-web/v2/beat-tracking/batch endpoint.
-
 
129
 
-
 
130
	// List of parties (stores) assigned to this auth user + their dtr.users.id
-
 
131
	@GetMapping(value = "/beatPlan/assignVisit/parties")
-
 
132
	public ResponseEntity<?> assignVisitParties(@RequestParam int authUserId) throws Exception {
-
 
133
		AuthUser au = authRepository.selectById(authUserId);
-
 
134
		if (au == null) return responseSender.badRequest("Auth user not found");
-
 
135
 
-
 
136
		// Map auth_user → dtr.users via email
-
 
137
		Integer dtrUserId = null;
-
 
138
		try {
-
 
139
			com.spice.profitmandi.dao.entity.dtr.User dtrUser =
-
 
140
					userRepositoryAuto.selectByEmailId(au.getEmailId());
-
 
141
			if (dtrUser != null) dtrUserId = dtrUser.getId();
-
 
142
		} catch (Exception ignored) {
-
 
143
		}
-
 
144
 
-
 
145
		Map<Integer, List<Integer>> mapping = csService.getAuthUserIdPartnerIdMapping();
-
 
146
		List<Integer> fofoIds = mapping.get(authUserId);
-
 
147
 
-
 
148
		List<Map<String, Object>> parties = new ArrayList<>();
-
 
149
		if (fofoIds != null && !fofoIds.isEmpty()) {
-
 
150
			List<FofoStore> stores = fofoStoreRepository.selectByRetailerIds(fofoIds);
-
 
151
			Map<Integer, CustomRetailer> retailerMap = retailerService.getFofoRetailers(fofoIds);
-
 
152
			for (FofoStore store : stores) {
-
 
153
				if (!store.isActive() || store.isClosed()) continue;
-
 
154
				CustomRetailer retailer = retailerMap.get(store.getId());
-
 
155
				Map<String, Object> p = new HashMap<>();
-
 
156
				p.put("fofoStoreId", store.getId());
-
 
157
				p.put("code", store.getCode());
-
 
158
				p.put("outletName", store.getOutletName() != null ? store.getOutletName()
-
 
159
						: (retailer != null ? retailer.getBusinessName() : "Store #" + store.getId()));
-
 
160
				p.put("latitude", store.getLatitude());
-
 
161
				p.put("longitude", store.getLongitude());
-
 
162
				p.put("city", retailer != null && retailer.getAddress() != null ? retailer.getAddress().getCity() : null);
-
 
163
				parties.add(p);
-
 
164
			}
-
 
165
			// Sort by code for stable display
-
 
166
			parties.sort((a, b) -> String.valueOf(a.get("code")).compareToIgnoreCase(String.valueOf(b.get("code"))));
-
 
167
		}
-
 
168
 
-
 
169
		Map<String, Object> result = new HashMap<>();
-
 
170
		result.put("dtrUserId", dtrUserId);
-
 
171
		result.put("authUserId", authUserId);
-
 
172
		result.put("userName", au.getFirstName() + " " + au.getLastName());
-
 
173
		result.put("parties", parties);
-
 
174
		return responseSender.ok(result);
-
 
175
	}
-
 
176
 
-
 
177
	// Submit assignment — accepts a JSON body, builds the v2 payload, posts it
-
 
178
	@PostMapping(value = "/beatPlan/assignVisit/submit")
-
 
179
	public ResponseEntity<?> assignVisitSubmit(
-
 
180
			HttpServletRequest request,
-
 
181
			@org.springframework.web.bind.annotation.RequestBody Map<String, Object> body) throws Exception {
-
 
182
 
-
 
183
		Integer authUserId = body.get("authUserId") != null ? ((Number) body.get("authUserId")).intValue() : null;
-
 
184
		String planDate = (String) body.get("planDate");
-
 
185
		List<Map<String, Object>> selected = (List<Map<String, Object>>) body.get("parties");
-
 
186
		if (authUserId == null || planDate == null || selected == null || selected.isEmpty()) {
-
 
187
			return responseSender.badRequest("authUserId, planDate and parties are required");
-
 
188
		}
-
 
189
 
-
 
190
		AuthUser au = authRepository.selectById(authUserId);
-
 
191
		if (au == null) return responseSender.badRequest("Auth user not found");
-
 
192
 
-
 
193
		// Map auth → dtr.users.id (this is the userId the v2 endpoint expects)
-
 
194
		com.spice.profitmandi.dao.entity.dtr.User dtrUser;
-
 
195
		try {
-
 
196
			dtrUser = userRepositoryAuto.selectByEmailId(au.getEmailId());
-
 
197
		} catch (Exception e) {
-
 
198
			return responseSender.badRequest("Failed to look up dtr.users for this auth user");
-
 
199
		}
-
 
200
		if (dtrUser == null) {
-
 
201
			return responseSender.badRequest("No dtr.users record found for auth user " + authUserId);
-
 
202
		}
-
 
203
		int dtrUserId = dtrUser.getId();
-
 
204
 
-
 
205
		// Persist directly via the shared DAO — mirrors BeatTrackingController.createBatch
-
 
206
		// in profitmandi-web. We can't autowire a controller across WARs, but
-
 
207
		// LocationTrackingRepository lives in profitmandi-dao and is shared.
-
 
208
		LocalDate taskDate;
-
 
209
		try {
-
 
210
			taskDate = LocalDate.parse(planDate);
-
 
211
		} catch (Exception e) {
-
 
212
			return responseSender.badRequest("Invalid planDate (expected yyyy-MM-dd): " + planDate);
-
 
213
		}
-
 
214
 
-
 
215
		LocalDateTime now = LocalDateTime.now();
-
 
216
		List<com.spice.profitmandi.dao.entity.auth.LocationTracking> created = new ArrayList<>();
-
 
217
 
-
 
218
		for (Map<String, Object> p : selected) {
-
 
219
			Integer fofoStoreId = ((Number) p.get("fofoStoreId")).intValue();
-
 
220
			String outletName = (String) p.get("outletName");
-
 
221
			String lat = (String) p.get("latitude");
-
 
222
			String lng = (String) p.get("longitude");
-
 
223
			String agenda = (String) p.get("agenda");
-
 
224
			if (agenda != null) agenda = agenda.trim();
-
 
225
			if (agenda == null || agenda.isEmpty()) agenda = "Visit";
-
 
226
 
-
 
227
			String visitLocation = (lat != null && lng != null && !lat.isEmpty() && !lng.isEmpty())
-
 
228
					? (lat + "," + lng) : "0.0000,0.0000";
-
 
229
 
-
 
230
			String displayName = (outletName != null && !outletName.isEmpty()) ? outletName : ("Store #" + fofoStoreId);
-
 
231
 
-
 
232
			com.spice.profitmandi.dao.entity.auth.LocationTracking row =
-
 
233
					new com.spice.profitmandi.dao.entity.auth.LocationTracking();
-
 
234
			row.setUserId(dtrUserId);
-
 
235
			row.setDeviceId("0");
-
 
236
			row.setTaskId(fofoStoreId);
-
 
237
			row.setTaskDate(taskDate);
-
 
238
			row.setTaskName(agenda + " | " + displayName);
-
 
239
			row.setTaskType("franchisee-visit");
-
 
240
			row.setMarkType("PENDING");
-
 
241
			row.setAddress("");
-
 
242
			row.setVisitLocation(visitLocation);
-
 
243
			row.setCheckInLatLng("0.0000,0.0000");
-
 
244
			row.setCheckOutLatLng("0.0000,0.0000");
-
 
245
			row.setCheckInTime(java.time.LocalTime.MIDNIGHT);
-
 
246
			row.setCheckOutTime(java.time.LocalTime.MIDNIGHT);
-
 
247
			row.setTransitTime(java.time.LocalTime.MIDNIGHT);
-
 
248
			row.setTimeSpent(java.time.LocalTime.MIDNIGHT);
-
 
249
			row.setEstimatedTime(java.time.LocalTime.MIDNIGHT);
-
 
250
			row.setSessionStartTime(java.time.LocalTime.MIDNIGHT);
-
 
251
			row.setSessionEndTime(java.time.LocalTime.MIDNIGHT);
-
 
252
			row.setTotalDistance("0.0");
-
 
253
			row.setStatus(false);
-
 
254
			row.setCreatedTimestamp(now);
-
 
255
			row.setUpdatedTimestamp(now);
-
 
256
 
-
 
257
			// Do NOT try/catch this — if persist throws, let it propagate so
-
 
258
			// @Transactional(rollbackFor = Throwable.class) rolls back cleanly.
-
 
259
			// Catching here lets Hibernate try to commit a broken session, which
-
 
260
			// then surfaces the misleading "null id in entry" flush error and hides
-
 
261
			// the real root cause (constraint violation, bad value, etc.).
-
 
262
			locationTrackingRepositoryAuto.persist(row);
-
 
263
			created.add(row);
-
 
264
		}
-
 
265
		LOGGER.info("assignVisit persisted {} location_tracking rows for dtrUserId={}", created.size(), dtrUserId);
-
 
266
 
-
 
267
		Map<String, Object> result = new HashMap<>();
-
 
268
		result.put("status", true);
-
 
269
		result.put("assignedCount", created.size());
-
 
270
		result.put("dtrUserId", dtrUserId);
-
 
271
		result.put("message", created.size() + " visit tasks assigned to " + au.getFirstName() + " " + au.getLastName());
-
 
272
		return responseSender.ok(result);
-
 
273
	}
-
 
274
 
119
	// ====================== BASE LOCATION MANAGEMENT ======================
275
	// ====================== BASE LOCATION MANAGEMENT ======================
120
	// Inline page that lets Sales L3+ pick a user and set their base (home)
276
	// Inline page that lets Sales L3+ pick a user and set their base (home)
121
	// location via map. Reads use the existing /beatPlan/getBaseLocation, writes
277
	// location via map. Reads use the existing /beatPlan/getBaseLocation, writes
122
	// go through the L3+-guarded endpoint below.
278
	// go through the L3+-guarded endpoint below.
123
	@GetMapping(value = "/beatPlan/baseLocationPage")
279
	@GetMapping(value = "/beatPlan/baseLocationPage")