原創 派單、搶單業務簡單實現


自動派單系統核心方法

@RestController
@RequestMapping(value="/api/client") // 通過這里配置使下面的映射都在/users下,可去除
@Api(description="【客戶端相關api接口】")
public class ApiClientController extends BaseApiResult {

@Autowired
private WeChatConfigService weChatConfigService;

@Autowired
APIBaseService apiBaseService;

@Autowired
APIUserService apiUserService;

@Autowired
APIOrderService apiOrderService;

@Autowired
APICouponService apiCouponService;


private static Logger logger = LoggerFactory.getLogger(ApiClientController.class);
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);



/**
 * 下單
 * http://localhost:8080/jiama/api/client/order?userId=1&productId=1&couponId=1&area=上海市 浦東新區&address=張江鎮益江路1000號…&phone=18321758957&lon=121.54664&lat=31.22593&cars=[{'carNo': '滬A12345', 'serviceDate': '2018-04-20 12:00:00'}, {'carNo': '滬12345', 'serviceDate': '2018-04-20 12:00:00'}]
 * 注意:一輛
 * @param userId
 * @param productId
 * @param lon
 * @param lat
 * @param phone
 * @param couponId
 * @param remarks
 * @param cars  [{'carNo': 'xxxx', 'serviceDate': '2018-04-20 12:00:00'}, {'carNo': 'xxxx', 'serviceDate': '2018-04-20 12:00:00'}]
 * @return
 */
@ApiOperation(value = "下單", response = BaseResult.class, notes = "下單")
@RequestMapping(value = "/order", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public String order(@ApiParam(name = "userId", value = "用戶id", required = true) @RequestParam String userId,
                    @ApiParam(name = "productId", value = "產品id", required = true) @RequestParam String productId,
                    @ApiParam(name = "area", value = "所在區域", required = true) @RequestParam String area,
                    @ApiParam(name = "address", value = "地址", required = true) @RequestParam String address,
                    @ApiParam(name = "phone", value = "手機號", required = true) @RequestParam String phone,
                    @ApiParam(name = "couponId", value = "優惠券id", required = false) @RequestParam(required = false) String couponId,
                    @ApiParam(name = "remarks", value = "備注", required = false) @RequestParam(required = false) String remarks,
                    @ApiParam(name = "cars", value = "車輛", required = true) @RequestParam String cars,
                    @ApiParam(name = "lon", value = "經度", required = true) @RequestParam String lon,
                    @ApiParam(name = "lat", value = "緯度", required = true) @RequestParam String lat,
                    @ApiParam(name = "shopId", value = "商鋪id", required = true) @RequestParam String shopId,
                    @ApiParam(name = "koucheId", value = "權益id", required = false) @RequestParam(required = false) String koucheId){
    // 0. 校驗手機號
    if (!ApiUtils.checkPhone(phone)) {
        return buildFailedResultInfo(BAD_REQUEST, "手機號不合法");
    }
    // 1. 將json轉換成JSONArray獲取每個車牌號並校驗車牌號的格式
    logger.info(cars);
    List<CarVO> carVOS = JSONObject.parseArray(cars, CarVO.class);
    List<Long> carIds = new ArrayList<>();
    Map<String, Object> product = apiBaseService.getByParam(TableEnum.jm_product, "*", "id", productId).get(0);
	int service_mins = (int) product.get("service_mins");
	Date pre_service_time = null;
	String carNo = null;
    for (CarVO carVO: carVOS) {
        carNo = carVO.getCarNo();
        pre_service_time = carVO.getServiceDate();
        if (!ApiUtils.checkCarNo(carNo)) {
            return buildFailedResultInfo(BAD_REQUEST, "車牌號不合法");
        } else if (!judgeServiceTimes(shopId, service_mins, pre_service_time)) {//判斷洗車時間是否有效
        	return buildFailedResultInfo(BAD_REQUEST, "當前洗車時間無效");
		} else {
            // 2. 判斷車牌號是否在jm_car 中,如果不存在插入該車輛的信息
            List<Map<String, Object>> carList = apiBaseService.getByParam(TableEnum.jm_car, "id", "car_no", carNo);
            long carId = 0;
            if (carList != null && carList.size() > 0) {
                carId = (int) carList.get(0).get("id");
            } else {
            	Map<String, Object> car = new HashMap<String, Object>();
            	car.put("carNo", carNo);
            	car.put("userId", userId);
                apiUserService.saveCar(car);
                carId = (long) car.get("id");
            }
            carIds.add(carId);
        }
    }
    // 3. 判斷優惠券是否可用
    Map<String, Object> coupon = null;
    if (couponId != null && couponId.length() > 0) {
        List<Map<String, Object>> coupons = apiBaseService.getByParam(TableEnum.jm_coupon, "*", "id", couponId);
        if (coupons != null && coupons.size() > 0) {
        	coupon = coupons.get(0);
            String error = validateCoupon(coupon, Integer.parseInt(userId), Integer.parseInt(productId));
            if (StringUtils.isNotEmpty(error)) {
                return buildFailedResultInfo(FORBIDDEN, error);
            }
        }
    }
    //判斷權益是否可用
    Map<String, Object> kouche = null;
    if (koucheId != null && koucheId.length() > 0) {
    	List<Map<String, Object>> kouches = apiCouponService.getKoucheById(carNo, koucheId, productId);
    	if (kouches.size() == 0) {
    		return buildFailedResultInfo(FORBIDDEN, "無法使用該權益");
		}
    	kouche = kouches.get(0);
	}
    long payAmount = (long) product.get("price");
    // 保存用戶訂單信息
    String orderNo = ApiUtils.getRandomNo(4);
    for (int i = 0; i < carIds.size(); i++) {
        Long carId = carIds.get(i);
        final Map<String, Object> order = new HashMap<String, Object>();
        order.put("user_id", userId);
        order.put("order_no", ApiUtils.getRandomNo(4));
        order.put("area", area);
        order.put("address", address);
        order.put("phone", phone);
        order.put("product_id", productId);
        order.put("car_id", carId);
        order.put("order_status", Constants.ORDER_STATUS_INIT);
        order.put("source_id", 1);
        order.put("remarks", remarks);
        order.put("type", 0);//0到店
        order.put("pre_service_time", carVOS.get(i).getServiceDate());
        order.put("pay_amount", payAmount);
        if (i == 0) {
        	order.put("order_no", orderNo);
        	if (coupon != null) {
        		payAmount = payAmount - (int)coupon.get("price");
        		order.put("coupon_id", couponId);
        		order.put("pay_amount", payAmount);
        		//優惠券修改狀態
        		Map<String, Object> pMap2 = new HashMap<String, Object>();
        		pMap2.put("id", couponId);
        		pMap2.put("status", Constants.COUPON_STATUS_USED);
        		apiBaseService.update(TableEnum.jm_coupon, pMap2, "id");
			}
        	if (kouche != null) {
        		payAmount = payAmount - (int)kouche.get("sum");
        		order.put("kouche_id", koucheId);
        		order.put("pay_amount", payAmount);
        		//權益修改狀態
        		Map<String, Object> pMap = new HashMap<String, Object>();
        		pMap.put("id", koucheId);
        		pMap.put("valid", Constants.KOUCHE_STATUS_USRD);
        		apiBaseService.update(TableEnum.jm_kouche, pMap, "id");
			}
        }
        order.put("create_date", new Date());
        String[] shop_ids = shopId.split(",");
        StringBuilder sb = new StringBuilder();
        boolean f = false;
        for (String id : shop_ids) {
        	Map<String, Object> shop = apiBaseService.getByParam(TableEnum.jm_shop, "*", "id", id).get(0);
        	if ((int)shop.get("type") == 0) {//先判斷直營店是否能分派技師並分派鎖定
        		if (judgeServiceTimes(id, service_mins, pre_service_time)) {
        			logger.info("直營店"+id+"嘗試分派技師,訂單編號:" + orderNo);
        			Map<String, Object> rMap = getTech(Constants.TECH_LEVEL_VIP, id, pre_service_time, productId);
        			if (rMap.size() == 0) {//派單給普通技師
        				rMap = getTech(Constants.TECH_LEVEL_NORMAL, id, pre_service_time, productId);
        			}
        			if (rMap.size() > 0) {
        				logger.info("訂單生成成功編號:" + orderNo + ";鎖定技師結果:" + rMap.get("tech_id"));
        				order.put("technician_id", rMap.get("tech_id"));
        				order.put("shop_id", id);
        				f = true;
        				break;
        			}
				}
        	} else {
				sb.append(id).append(",");
			}
		}
        if (!f) {//直營店均未能分派技師,轉加盟商
        	JedisUtils.hsetnx("orderShop", orderNo, sb.toString());
		}
        apiOrderService.saveOrder(order, area, address, userId);
        if (payAmount <= 0) {// 直接修改訂單狀態,並走搶/派單邏輯
        	order.put("id", apiBaseService.getByParam(TableEnum.jm_order, "id", "order_no", orderNo).get(0).get("id"));
        	Map<String, Object> pMap = new HashMap<String, Object>();
        	pMap.put("order_no", orderNo);
        	pMap.put("order_status", Constants.ORDER_STATUS_NO_ACCEPT);
        	apiBaseService.update(TableEnum.jm_order, pMap, "order_no");
        	fixedThreadPool.execute(new Runnable() {
        		@Override
        		public void run() {
        			systemAutoAssign(order);
        		}
        	});
        }
    }
    
    return buildSuccessResultInfo(orderNo);
}

   
@ApiOperation(value = "根據經緯度獲取商鋪,技師等信息", response = BaseResult.class, notes = "根據經緯度獲取商鋪,技師等信息")
@RequestMapping(value = "/infosBylnla", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public String getInfosBylnla(@ApiParam(name = "lon", value = "經度", required = true) @RequestParam String lon,
		@ApiParam(name = "lat", value = "緯度", required = true) @RequestParam String lat,
		@ApiParam(name = "product_id", value = "商品id", required = true) @RequestParam String product_id) {
	Map<String, String> orderLocation = new HashMap<String, String>();
	orderLocation.put("X", lat);//121.47888,31.262438;117.228117,31.830429;121.481728,31.262569
	orderLocation.put("Y", lon);
	List<Map<String, Object>> shopList = apiUserService.getShopForTimes();
	//遍歷商鋪,先遍歷直營店
	StringBuilder shop_id = new StringBuilder();
	for (Map<String, Object> map : shopList) {
		if (apiOrderService.getShopForOrder(map.get("id").toString(), product_id).size() > 0) {//產品有配
			Map<String, Object> zoneMap = apiBaseService.getByParam(TableEnum.jm_zone, "point", "id", map.get("zone_id").toString()).get(0);
			//獲取商品區域頂點
			String partitionLocation = (String)zoneMap.get("point");
			if (!StringUtils.isEmpty(partitionLocation)) {
				if (MapUtils.isInPolygon(orderLocation, partitionLocation)) {//該商鋪區域合適
					shop_id.append(map.get("id")).append(",");
				}
			}
		}
	}
	if (shop_id.length() > 0) {
		return buildSuccessResultInfo(shop_id.toString());
	}
    return buildFailedResultInfo(BAD_REQUEST, "所選位置不在服務范圍內!");
}

@ApiOperation(value = "根據商鋪日期獲取可服務時間信息", response = BaseResult.class, notes = "根據商鋪日期獲取可服務時間信息")
@RequestMapping(value = "/serviceTimes", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public String getServiceTimes(@ApiParam(name = "shopId", value = "商鋪id", required = true) @RequestParam String shopId,
		@ApiParam(name = "date", value = "日期", required = true) @RequestParam String date,
		@ApiParam(name = "service_mins", value = "商品服務時長", required = true) @RequestParam int service_mins) {
	//區域重合店鋪,時間段
	String[] shopids = shopId.split(",");
	Set<String> times = new HashSet<String>();
	boolean f = false;
	int count = 0;
	//先獲取每個商品對應不可選時段
	Map<String, Integer> map = new HashMap<String, Integer>();
	for (int i = 0; i < shopids.length; i++) {
		Set<String> ts = getSvTimes(shopids[i], date, service_mins);
		if (ts == null) {
			continue;
		}
		if (ts.size() == 0) {
			return buildSuccessResultInfo(times);
		}
		f = true;
		count++;
		for (String s : ts) {
			if (map.containsKey(s)) {
				map.put(s, map.get(s)+1);
			} else {
				map.put(s, 1);
			}
		}
	}
	if (!f) {
		return buildFailedResultInfo(BAD_REQUEST, "暫無服務技師");
	}
	for (Entry<String, Integer> e : map.entrySet()) {
		if (e.getValue() == count) {
			times.add(e.getKey());
		}
	}
	return buildSuccessResultInfo(times);
}

@ApiOperation(value = "判斷可服務時間true可支付", response = BaseResult.class, notes = "判斷可服務時間")
@RequestMapping(value = "/judgeServiceTime", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public String judgeServiceTime(@ApiParam(name = "shopId", value = "商鋪id", required = true) @RequestParam String shopId,
		@ApiParam(name = "service_mins", value = "商品服務時長", required = true) @RequestParam int service_mins,
		@ApiParam(name = "pre_service_time", value = "洗車時間", required = true) @RequestParam long pre_service_time) {
	List<Map<String, Object>> techList = apiUserService.getTechForTimes(shopId);
	//獲取同一時間待服務中訂單是否大於等於技師數量
	if (techList.size() > 0) {
		String[] pre_service = DateUtils.formatDate(new Date(pre_service_time), "yyyy-MM-dd HH:mm").split("\\s");
		List<Map<String, Object>> preTimeList = apiOrderService.getOrderByNum(shopId, techList.size(), pre_service[0]);
		Set<String> times = new HashSet<String>();
		for (Map<String, Object> map2 : preTimeList) {
			int mins = (int)map2.get("service_mins");
			Date d = (Date) map2.get("pre_service_time");
			times.add(DateUtils.formatDate(d, "HH:mm"));
			for (int i = 1; i < mins/30.0; i++) {
				d = DateUtils.addMinutes(d, 30);
				times.add(DateUtils.formatDate(d, "HH:mm"));
			}
			d = (Date) map2.get("pre_service_time");
			for (int i = 1; i < service_mins/30.0; i++) {
				d = DateUtils.addMinutes(d, -30);
				times.add(DateUtils.formatDate(d, "HH:mm"));
			}
		}
		return buildSuccessResultInfo(!times.contains(pre_service[1]));
	}
	return buildSuccessResultInfo(false);
}

@ApiOperation(value = "獲取未過期最近的優惠券", response = BaseResult.class, notes = "獲取未過期最近的優惠券")
@RequestMapping(value = "/getLastCoupon", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String getLastCoupon(@ApiParam(name = "userId", value = "用戶id", required = true) @RequestParam String userId,
		@ApiParam(name = "productId", value = "商品id", required = true) @RequestParam String productId){
    List<Map<String, Object>> coupons = apiCouponService.getCouponByProduct(userId, productId);
    Map<String, Object> coupon = coupons.size()>0?coupons.get(0):null;
    return buildSuccessResultInfo(coupon);
}



@ApiOperation(value = "取消訂單", response = BaseResult.class, notes = "取消訂單")
@RequestMapping(value = "/cancelOrder", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public String cancelOrder(@ApiParam(name = "orderId", value = "訂單id", required = true) @RequestParam String orderId,
		@ApiParam(name = "cancelReason", value = "取消原因", required = false) @RequestParam(required = false) String cancelReason){
	//判斷該訂單狀態為未開始服務
	List<Map<String, Object>> rList = apiBaseService.getByParam(TableEnum.jm_order, "*", "id", orderId);
	if (rList.size() == 0) {
		return buildFailedResultInfo(BAD_REQUEST, "參數錯誤");
	}
	Map<String, Object> rMap = rList.get(0);
	int order_status = (int) rMap.get("order_status");
	Map<String, Object> pMap = new HashMap<String, Object>();
	pMap.put("id", orderId);
	pMap.put("order_status", Constants.ORDER_STATUS_CANCEL);
	try {
		pMap.put("cancel_reason", URLDecoder.decode(cancelReason, "utf-8"));
	} catch (UnsupportedEncodingException e) {
		logger.info("decode_error", e);
	}
	if (order_status != Constants.ORDER_STATUS_IN_SERVICE && order_status != Constants.ORDER_STATUS_END_SERVICE) {//服務中,服務完成
		apiBaseService.update(TableEnum.jm_order, pMap, "id");
		//推送技師
		Map<String, Object> techMap = new HashMap<String, Object>();
		if (rMap.get("technician_id") != null) {
			techMap = apiBaseService.getByParam(TableEnum.jm_technician, "*", "id", rMap.get("technician_id").toString()).get(0);
			try {
				WeiXinUtil.sendText(techMap.get("open_id").toString(), "<a href=\""+Global.getConfig("techPage")+"\">您有訂單已取消!</a>", false);
			} catch (Exception e) {
				logger.info("取消訂單推送技師失敗", e);
			}
		}
		//推送模板消息給用戶已取消
		Map<String, Object> pMap3 = new HashMap<String, Object>();
		Map<String, Object> userMap = apiBaseService.getByParam(TableEnum.jm_user, "*", "id", rMap.get("user_id").toString()).get(0);
		pMap3.put("openId", userMap.get("wx_open_id"));
		pMap3.put("templateId", Global.getConfig("templateId_cancel"));
		pMap3.put("first", "您預約的服務已取消!");
		pMap3.put("keyword1", userMap.get("nickname"));
		pMap3.put("keyword2", userMap.get("phone"));
		pMap3.put("keyword3", DateUtils.formatDate((Date)rMap.get("pre_service_time"), "yyyy-MM-dd HH:mm"));
		pMap3.put("keyword4", userMap.get("adderss"));
		pMap3.put("keyword5", userMap.get("adderss"));
		WeiXinUtil.sendWxTemplate(pMap3);
		if (rMap.get("coupon_id") != null) {//退回優惠券
			Map<String, Object> pMap2 = new HashMap<String, Object>();
			pMap2.put("id", rMap.get("coupon_id"));
			pMap2.put("status", Constants.COUPON_STATUS_ACTIVED);
			apiBaseService.update(TableEnum.jm_coupon, pMap2, "id");
		}
		//退回權益
		if (rMap.get("kouche_id") != null) {
			Map<String, Object> pMap2 = new HashMap<String, Object>();
			pMap2.put("id", rMap.get("kouche_id"));
			pMap2.put("valid", Constants.KOUCHE_STATUS_NOUSE);
			apiBaseService.update(TableEnum.jm_kouche, pMap2, "id");
		}
	} else {
		return buildFailedResultInfo(BAD_REQUEST, "無法取消");
	}
    return buildSuccessResultInfo();
}

// 我的訂單
@ApiOperation(value = "我的訂單列表", response = BaseResult.class, notes = "我的訂單列表")
@RequestMapping(value = "/orders", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String getMyOrders(@ApiParam(name = "userId", value = "用戶id", required = true) @RequestParam String userId,
                          @ApiParam(name = "orderStatus", value = "訂單狀態", required = false) @RequestParam(required = false) String orderStatus) {
	List<Map<String, Object>> rList = null;
	if (orderStatus == null) {
		rList = apiOrderService.getMyOrder(userId);
	} else {
		rList = apiOrderService.getMyOrderByStatus(userId, orderStatus);
	}
	for (Map<String, Object> map : rList) {
		map.put("now", new Date());
		map.put("end_time", DateUtils.addMinutes((Date)map.get("create_date"), Integer.valueOf(Global.getConfig("pay_time"))));
		List<Map<String, Object>> rList2 = apiOrderService.getEvaluate(userId, map.get("id").toString());
		map.put("evaluate", false);
		if (rList2.size() > 0) {//已評價
			map.put("evaluate", true);
		}
	}
    return buildSuccessResultInfo(rList);
}

/*@ApiOperation(value = "車輛報告", response = BaseResult.class, notes = "車輛報告")
@RequestMapping(value = "/carReport", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String carReport(HttpServletRequest request, HttpServletResponse response,
                          @ApiParam(name = "orderId", value = "車輛id", required = true) @RequestParam long orderId) {
	CarReport carReport = carReportService.findUniqueByProperty("order_id", orderId);

    return buildSuccessResultInfo(carReport);
}


// 參考漫魚 OneStepOrderAction.java
@RequestMapping(value = "/payment", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public String payment() {
    // 支付寶支付、微信支付
    // 返回支付地址供前端調用
    return null;
}
*/
@RequestMapping(value = "/wechat/pay/callback", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public void wechatPayNotify(@RequestBody String callBackData, HttpServletResponse response) throws IOException, DocumentException {
	logger.info("微信支付回調開始....返回數據:" + callBackData);
	SortedMap<String, String> smap = dom4jXMLParse(callBackData);
	
	Map<String, Object> rMap = new HashMap<String, Object>();
	if ("SUCCESS".equals(smap.get("return_code").toString())) {//支付成功
		//MD5驗證
		if (!isWechatSign(smap, Global.getConfig("MY_WEBCHAT_APPKEY"))) {
	    	String resXml = "<xml>"
					+ "<return_code>FAIL</return_code>"
					+ "<return_msg>簽名失敗</return_msg>"
					+ "</xml>";
	    	BufferedOutputStream out = new BufferedOutputStream(
                    response.getOutputStream());
            out.write(resXml.getBytes());
            out.flush();
            out.close();
            return;
		}
		
		// 修改訂單狀態,更新微信訂單號,實際支付金額,支付完成時間
		String orderNo = smap.get("out_trade_no");
		logger.info("****************************************支付回掉訂單號:"+orderNo);
		
		List<Map<String, Object>> orderList = apiBaseService.getByParam(TableEnum.jm_order, "*", "order_no", orderNo);
		if (orderList.size() == 0) {
	    	String resXml = "<xml>"
					+ "<return_code>FAIL</return_code>"
					+ "<return_msg>訂單號錯誤</return_msg>"
					+ "</xml>";
	    	BufferedOutputStream out = new BufferedOutputStream(
                    response.getOutputStream());
            out.write(resXml.getBytes());
            out.flush();
            out.close();
            return;
		}
		final Map<String, Object> order = orderList.get(0);
		Map<String, Object> pMap = new HashMap<String, Object>();
		pMap.put("order_no", orderNo);
		pMap.put("wx_order_no", smap.get("transaction_id"));
		pMap.put("real_pay_amount", smap.get("cash_fee"));
		pMap.put("pay_time", smap.get("time_end"));
		pMap.put("order_status", Constants.ORDER_STATUS_NO_ACCEPT);
		apiBaseService.update(TableEnum.jm_order, pMap, "order_no");
		// 如果使用了優惠券,將優惠券的狀態改成已使用2
		/*if (order.get("coupon_id") != null) {
			int couponId = (int) order.get("coupon_id");
			Map<String, Object> pMap2 = new HashMap<String, Object>();
    		pMap2.put("id", couponId);
    		pMap2.put("status", Constants.COUPON_STATUS_USED);
    		apiBaseService.update(TableEnum.jm_coupon, pMap2, "id");
		}*/
		// 如果支付成功,根據規則安排相應的技師處理,並通知技師(在微信公眾號中給用戶推送通知) 參考派單原則(原型)
		fixedThreadPool.execute(new Runnable() {
			@Override
			public void run() {
				systemAutoAssign(order);
			}
		});
		rMap.put("return_code", "SUCCESS");
		String resXml = "<xml>"
				+ "<return_code>SUCCESS</return_code>"
				+ "<return_msg>OK</return_msg>"
				+ "</xml>";
    	BufferedOutputStream out = new BufferedOutputStream(
                response.getOutputStream());
        out.write(resXml.getBytes());
        out.flush();
        out.close();
        return;
	}
	String resXml = "<xml>"
			+ "<return_code>FAIL</return_code>"
			+ "<return_msg>支付失敗</return_msg>"
			+ "</xml>";
	BufferedOutputStream out = new BufferedOutputStream(
            response.getOutputStream());
    out.write(resXml.getBytes());
    out.flush();
    out.close();
    return;
}

@SuppressWarnings("rawtypes")
private static SortedMap<String, String> dom4jXMLParse(String strXML) throws DocumentException {
	SortedMap<String, String> smap = new TreeMap<String, String>();
	Document doc = DocumentHelper.parseText(strXML);
	Element root = doc.getRootElement();
	for (Iterator iterator = root.elementIterator(); iterator.hasNext();) {
		Element e = (Element) iterator.next();
		smap.put(e.getName(), e.getText());
	}
	return smap;
}

@SuppressWarnings("rawtypes")
public static boolean isWechatSign(SortedMap<String, String> smap,String apiKey) {
    StringBuffer sb = new StringBuffer();
    Set es = smap.entrySet();
    Iterator it = es.iterator();
    while (it.hasNext()) {
        Map.Entry entry = (Map.Entry) it.next();
        String k = (String) entry.getKey();
        String v = (String) entry.getValue();
        if (!"sign".equals(k) && null != v && !"".equals(v) && !"key".equals(k)) {
            sb.append(k + "=" + v + "&");
        }
    }
    sb.append("key=" + apiKey);
    /** 驗證的簽名 */
    String sign = EncryptHelp.getMD5Str(sb.toString());
    /** 微信端返回的合法簽名 */
    String validSign = smap.get("sign").toUpperCase();
    return validSign.equals(sign);
}

// 系統自動派單
public void systemAutoAssign(Map<String, Object> order) {
    // 根據shop_id查找對應商鋪並查找出對應技師
	Date pre_service_time = (Date) order.get("pre_service_time");
	String productId = order.get("product_id").toString();
	String orderId = order.get("id").toString();
	String orderNo = order.get("order_no").toString();
	//判斷商鋪是否是加盟商
	if (order.get("technician_id") == null) {
		boolean f = false;
		String shopId = JedisUtils.hget("orderShop", orderNo);
		String[] shop_ids = shopId.split(",");
		logger.info("搶單開始,訂單號:" + orderNo);
		for (String id: shop_ids) {
			//獲取可選技師
			Set<String> rSet = getTechForComplete(id, pre_service_time, productId);
			logger.info("搶單訂單號:" + orderNo + ";搶單商鋪"+id+",技師數量結果:" + rSet.size());
			StringBuilder sb = new StringBuilder();
			for (String s : rSet) {
				sb.append(s).append(",");
				Map<String, Object> vipTech = apiBaseService.getByParam(TableEnum.jm_technician, "*", "id", s).get(0);
				if (1 == (int)vipTech.get("is_vip")) {//vip技師
					f = true;
					try {
						WeiXinUtil.sendText(vipTech.get("open_id").toString(), "<a href=\""+Global.getConfig("completePage")+"?user_id="+s+"&order_id="+orderId+"\">有新的訂單了!點擊搶單!</a>", false);
					} catch (Exception e) {
						logger.info("搶單推送技師失敗", e);
					}
					JedisUtils.set("complete_" + orderId, id, 600);
				}
			}
			JedisUtils.hsetnx("tid_"+orderId, id, sb.toString());
			JedisUtils.expire("tid_"+orderId, 3600);
		}
		if (!f) {
			String[] cs = JedisUtils.get("customer_service").split(",");
			try {
				for (int i = 0; i < cs.length; i++) {
					WeiXinUtil.sendText(cs[i], "有未派單搶單!", false);
				}
			} catch (Exception e) {
				logger.info("搶單推送運營失敗", e);
			}
		}
	} else {
		String technician_id = order.get("technician_id").toString();
		logger.info("支付成功推送技師,訂單號:" + orderId + "技師id:"+ technician_id);
		Map<String, Object> techMap = apiBaseService.getByParam(TableEnum.jm_technician, "*", "id", technician_id).get(0);
		try {
			WeiXinUtil.sendText(techMap.get("open_id").toString(), "<a href=\""+Global.getConfig("techPage")+"\">您好,您有新的服務訂單!</a>", false);
		} catch (Exception e) {
			logger.info("派單推送技師失敗", e);
		}
		//推送模板消息給用戶,已派單
		Map<String, Object> pMap3 = new HashMap<String, Object>();
		Map<String, Object> userMap = apiBaseService.getByParam(TableEnum.jm_user, "*", "id", order.get("user_id").toString()).get(0);
		pMap3.put("openId", userMap.get("wx_open_id"));
		pMap3.put("templateId", Global.getConfig("templateId_assign"));
		pMap3.put("first", "您好,您的訂單已接單!");
		pMap3.put("keyword1", techMap.get("name"));
		pMap3.put("keyword2", techMap.get("phone"));
		pMap3.put("keyword3", DateUtils.formatDate(pre_service_time, "yyyy-MM-dd HH:mm"));
		WeiXinUtil.sendWxTemplate(pMap3);
	}
}

    
@ApiOperation(value = "派單成功推送客戶模板消息", response = BaseResult.class, notes = "派單成功推送客戶模板消息")
@RequestMapping(value = "/sendUserTemp", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String sendUserTemp(@ApiParam(name = "orderId", value = "訂單id", required = true) @RequestParam String orderId,
		@ApiParam(name = "state", value = "模板類型1取消,2完成,3接單", required = true) @RequestParam int state) throws Exception {
	Map<String, Object> orderMap = apiBaseService.getByParam(TableEnum.jm_order, "*", "id", orderId).get(0);
	Map<String, Object> userMap = apiBaseService.getByParam(TableEnum.jm_user, "*", "id", orderMap.get("user_id").toString()).get(0);
	Map<String, Object> pMap3 = new HashMap<String, Object>();
	if (1 == state) {
		pMap3.put("openId", userMap.get("wx_open_id"));
		pMap3.put("templateId", Global.getConfig("templateId_cancel"));
		pMap3.put("first", "您預約的服務已取消!");
		pMap3.put("keyword1", userMap.get("nickname"));
		pMap3.put("keyword2", userMap.get("phone"));
		pMap3.put("keyword3", DateUtils.formatDate((Date)orderMap.get("pre_service_time"), "yyyy-MM-dd HH:mm"));
		pMap3.put("keyword4", userMap.get("adderss"));
		pMap3.put("keyword5", userMap.get("adderss"));
	} else if (2 == state) {
		pMap3.put("openId", userMap.get("wx_open_id"));
		pMap3.put("templateId", Global.getConfig("templateId_end"));
		pMap3.put("first", "服務已完成,感謝您選擇甲馬服務!");
		pMap3.put("keyword1", DateUtils.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss"));
		pMap3.put("keyword2", orderMap.get("order_no"));
	} else {
		pMap3.put("openId", userMap.get("wx_open_id"));
		pMap3.put("templateId", Global.getConfig("templateId_assign"));
		pMap3.put("first", "您好,您的訂單已接單!");
		Map<String, Object> techMap = apiBaseService.getByParam(TableEnum.jm_technician, "*", "id", orderMap.get("technician_id").toString()).get(0);
		pMap3.put("keyword1", techMap.get("name"));
		pMap3.put("keyword2", techMap.get("phone"));
		pMap3.put("keyword3", DateUtils.formatDate((Date)orderMap.get("pre_service_time"), "yyyy-MM-dd HH:mm"));
	}
	WeiXinUtil.sendWxTemplate(pMap3);
	return buildSuccessResultInfo();
}

    
private String validateCoupon(Map<String, Object> coupon, Integer userId, Integer productId){
    if (coupon == null) {
        return "優惠券不存在";
    }
    // 判斷優惠券是否存並且是未激活狀態
    Integer status = (Integer) coupon.get("status");
    if (status == Constants.COUPON_STATUS_NOT_ACTIVE) {
    	return  "優惠券尚未綁定";
    } else if (status == Constants.COUPON_STATUS_USED) {
    	return  "優惠券已使用";
    }
    // 判斷時間段
    Date beginTime = (Date) coupon.get("begin_time");
    Date endTime = (Date) coupon.get("end_time");
    Date now = new Date();
    if (!DateUtils.isInRange(beginTime, now, endTime)) {
    	return  "該時間段不允許使用此優惠券";
    }
    // 如果優惠碼指定某個用戶使用還要校驗是否為該用戶
    Integer userIdForCoupon = (Integer) coupon.get("user_id");
    if (userIdForCoupon == null) {
    	return  "優惠券尚未綁定用戶";
    } else if(userIdForCoupon - userId != 0){
    	return  "優惠券綁定用戶不匹配";
    }
    if (coupon.get("product_id") != null) {
        Integer productID = (Integer) coupon.get("product_id");
        if (productID - productId != 0) {
        	return  "該服務不能使用該優惠券";
        }
    }

    return null;
}

private Map<String, Object> getTech(String level, String shopId, Date pre_service_time, String productId) {
	Map<String, Object> rMap = new HashMap<String, Object>();
	List<Map<String, Object>> techList = apiUserService.getTechByLevelForOrder(shopId, level, DateUtils.formatDate(pre_service_time, "yyyy-MM-dd HH:mm:ss"));
	if (techList.size() > 0) {
		List<Map<String, Object>> techList2 = apiUserService.getTechByLevelForOrder2(shopId, level, DateUtils.formatDate(pre_service_time, "yyyy-MM-dd"));
		if (techList2.size() > 0) {//該預約時間之前無訂單及之后無訂單
			rMap.put("tech_id", techList2.get(0).get("id").toString());
			rMap.put("open_id", techList2.get(0).get("open_id").toString());
			rMap.put("name", techList2.get(0).get("name").toString());
			rMap.put("phone", techList2.get(0).get("phone").toString());
		} else {
			//有訂單的技師排序
			List<String> techIds = new ArrayList<String>();
			for (Map<String, Object> map : techList) {
				techIds.add(map.get("id").toString());
			}
			Map<String, Object> pMap = new HashMap<String, Object>();
			pMap.put("techIds", techIds);
			pMap.put("date", DateUtils.formatDate(pre_service_time, "yyyy-MM-dd"));
			List<Map<String, Object>> techList3 =  apiUserService.getTechOrderNum(pMap);
			Map<String, Object> productMap = apiBaseService.getByParam(TableEnum.jm_product, "*", "id", productId).get(0);
			int service_mins = (int) productMap.get("service_mins");
			Date service_end = DateUtils.addMinutes(pre_service_time, service_mins);
			for (Map<String, Object> map : techList3) {
				String t_id = map.get("technician_id").toString();
				Map<String, Object> techMap = apiBaseService.getByParam(TableEnum.jm_technician, "*", "id", t_id).get(0);
				String workTime = (String) techMap.get("service_time");
				if (!ApiUtils.judgeWorkTime(workTime, pre_service_time) || (int)techMap.get("status") == 2 || techMap.get("open_id") == null) {
					continue;
				}
				//獲取洗車結束時間內有無訂單
				List<Map<String, Object>> orders = apiUserService.getTechByLevelForOrder3(t_id, DateUtils.formatDate(service_end, "yyyy-MM-dd HH:mm:ss"));
				if (orders.size() == 0) {
					rMap.put("tech_id", t_id);
					rMap.put("open_id", techMap.get("open_id").toString());
					rMap.put("name", techMap.get("name").toString());
					rMap.put("phone", techMap.get("phone").toString());
					break;
				} else {//查看最后一單時間是否合適
					Map<String, Object> od = orders.get(0);
					Date d1 = DateUtils.addMinutes((Date)od.get("pre_service_time"), (int)od.get("service_mins"));
					if (d1.before(pre_service_time)) {//上一單時間不超出預約時間
						rMap.put("tech_id", t_id);
						rMap.put("open_id", techMap.get("open_id").toString());
						rMap.put("name", techMap.get("name").toString());
						rMap.put("phone", techMap.get("phone").toString());
						break;
					}
				}
			}
		}
	}
	
	return rMap;
}

private Set<String> getTechForComplete(String shopId, Date pre_service_time, String productId) {
	Set<String> idSet = new HashSet<String>();
	List<Map<String, Object>> techList = apiUserService.getTechForOrder(shopId, DateUtils.formatDate(pre_service_time, "yyyy-MM-dd HH:mm:ss"));
	if (techList.size() > 0) {
		List<Map<String, Object>> techList2 = apiUserService.getTechForOrder2(shopId, DateUtils.formatDate(pre_service_time, "yyyy-MM-dd"));
		if (techList2.size() > 0) {//該預約時間之前無訂單及之后無訂單
			for (Map<String, Object> map : techList2) {
				if (map.get("open_id") != null) {
					idSet.add(map.get("id").toString());
				}
			}
		}
		//有訂單的技師排序
		List<String> techIds = new ArrayList<String>();
		for (Map<String, Object> map : techList) {
			techIds.add(map.get("id").toString());
		}
		Map<String, Object> pMap = new HashMap<String, Object>();
		pMap.put("techIds", techIds);
		pMap.put("date", DateUtils.formatDate(pre_service_time, "yyyy-MM-dd"));
		List<Map<String, Object>> techList3 =  apiUserService.getTechOrderNum(pMap);
		Map<String, Object> productMap = apiBaseService.getByParam(TableEnum.jm_product, "*", "id", productId).get(0);
		int service_mins = (int) productMap.get("service_mins");
		Date service_end = DateUtils.addMinutes(pre_service_time, service_mins);
		for (Map<String, Object> map : techList3) {
			String t_id = map.get("technician_id").toString();
			Map<String, Object> techMap = apiBaseService.getByParam(TableEnum.jm_technician, "*", "id", t_id).get(0);
			String workTime = (String) techMap.get("service_time");
			if (!ApiUtils.judgeWorkTime(workTime, pre_service_time) || (int)techMap.get("status") == 2 || techMap.get("open_id") == null) {
				continue;
			}
			//獲取洗車結束時間內有無訂單
			List<Map<String, Object>> orders = apiUserService.getTechByLevelForOrder3(t_id, DateUtils.formatDate(service_end, "yyyy-MM-dd HH:mm:ss"));
			if (orders.size() == 0) {
				idSet.add(techMap.get("id").toString());
			} else {//查看最后一單時間是否合適
				Map<String, Object> od = orders.get(0);
				Date d1 = DateUtils.addMinutes((Date)od.get("pre_service_time"), (int)od.get("service_mins"));
				if (d1.before(pre_service_time)) {//上一單時間不超出預約時間
					idSet.add(techMap.get("id").toString());
				}
			}
		}
	}
	return idSet;
}

private boolean judgeServiceTimes(String shopId, int service_mins, Date pre_service_time) {
	String[] shopids = shopId.split(",");
	Set<String> times = new HashSet<String>();
	int count = 0;
	//先獲取每個商品對應不可選時段
	Map<String, Integer> map = new HashMap<String, Integer>();
	boolean flag = false;
	String[] pre_service = DateUtils.formatDate(pre_service_time, "yyyy-MM-dd HH:mm").split("\\s");
	for (int i = 0; i < shopids.length; i++) {
		Set<String> ts = getSvTimes(shopids[i], pre_service[0], service_mins);
		if (ts == null) {
			continue;
		}
		if (ts.size() == 0) {
			return true;
		}
		flag = true;
		count++;
		for (String s : ts) {
			if (map.containsKey(s)) {
				map.put(s, map.get(s)+1);
			} else {
				map.put(s, 1);
			}
		}
	}
	if (!flag) {
		return false;
	}
	for (Entry<String, Integer> e : map.entrySet()) {
		if (e.getValue() == count) {
			times.add(e.getKey());
		}
	}
	return !times.contains(pre_service[1]);
}


}

簡單實現完成


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM