대시보드, 기기에러, 계정관리 수정

This commit is contained in:
comicgum
2026-09-15 21:52:40 +09:00
parent 4a6c9d2afe
commit d1e230eb6a
32 changed files with 1984 additions and 73 deletions
@@ -195,6 +195,8 @@ public class _AG {
uri.compareTo("/api/terminal-state.do") == 0 ||
uri.compareTo("/api/sign-in.do") == 0 ||
uri.compareTo("/api/sval2.do") == 0 ||
uri.compareTo("/api/send-sms-test.do") == 0 || //TempCode: SMS integration test, remove when done
uri.compareTo("/api/add-device-error.do") == 0 ||
uri.compareTo("/api/add-transaction.do") == 0) {
return true;
}
@@ -0,0 +1,133 @@
package com.handong.smartservice.component;
import java.util.ArrayList;
import java.util.List;
/**
* Decoder for the "자판기 이상 DATA (DC = 0x03)" telegram stored in device_error.error_code.
* Spec: 카드리더기_롯데_통신전문_추가사양_할부결제_요청 문서 10.3 (5 ~ 15 byte 가변)
*
* byte 1 bit0~7 : 대표이상 / 코인메카니즘 / 지폐식별기 / 물없음 / 온수저온 / 얼음품절 / 컵품절·컵걸림 / 배수부 가득참
* byte 2 bit0~6 : System 이상 / 기타 이상 / Bucket 이상 / Door Open / 슬레이브 이상 / Reserved / Reserved
* byte 3~14 : 품절 컬럼 1 ~ 96 (byte 당 8 컬럼)
* byte 15 : 하위니블 = 품절 컬럼 97~99, 상위니블 = 컬럼 백의자리(0~9)
*/
public class DeviceErrorCode {
public static final String STATE_FAULT = "이상";
public static final String STATE_SOLD_OUT = "품절";
private static final String[] BYTE1_LABELS = {
"대표이상",
"코인메카니즘 관련 이상",
"지폐식별기 관련 이상",
"물없음",
"온수저온",
"얼음품절",
"컵품절 또는 컵걸림",
"배수부 가득참",
};
private static final String[] BYTE2_LABELS = {
"System 이상",
"기타 이상",
"Bucket 이상",
"Door Open",
"슬레이브 이상",
"Reserved(14)",
"Reserved(15)",
};
private static int[] toBytes(String error_code) {
if (error_code == null)
return new int[0];
String hex = error_code.trim();
if (hex.length() < 2 || hex.length() % 2 != 0 || hex.matches(".*[^0-9a-fA-F].*"))
return new int[0];
int[] bytes = new int[hex.length() / 2];
for (int i = 0; i < bytes.length; i++)
bytes[i] = Integer.parseInt(hex.substring(i * 2, i * 2 + 2), 16);
return bytes;
}
/** 대표이상을 제외한 단말기 이상 목록 */
public static List<String> getFaults(String error_code) {
int[] bytes = toBytes(error_code);
List<String> faults = new ArrayList<>();
if (bytes.length == 0)
return faults;
for (int bit = 1; bit < 8; bit++) {
if ((bytes[0] & (1 << bit)) != 0)
faults.add(BYTE1_LABELS[bit]);
}
if (bytes.length >= 2) {
for (int bit = 0; bit < 7; bit++) {
if ((bytes[1] & (1 << bit)) != 0)
faults.add(BYTE2_LABELS[bit]);
}
}
return faults;
}
/** 품절 컬럼번호 목록 */
public static List<Integer> getSoldOutColumns(String error_code) {
int[] bytes = toBytes(error_code);
List<Integer> columns = new ArrayList<>();
if (bytes.length == 0)
return columns;
// The last byte carries the hundreds digit of the column number in its upper nibble
int hundreds = bytes.length >= 15 ? (bytes[14] >> 4) & 0x0f : 0;
int base = hundreds * 100;
int last = Math.min(bytes.length, 14);
for (int index = 2; index < last; index++) {
for (int bit = 0; bit < 8; bit++) {
if ((bytes[index] & (1 << bit)) != 0)
columns.add(base + (index - 2) * 8 + bit + 1);
}
}
if (bytes.length >= 15) {
for (int bit = 0; bit < 3; bit++) {
if ((bytes[14] & (1 << bit)) != 0)
columns.add(base + 97 + bit);
}
}
return columns;
}
public static boolean hasRepresentative(String error_code) {
int[] bytes = toBytes(error_code);
return bytes.length > 0 && (bytes[0] & 0x01) != 0;
}
/** One line summary of the telegram, shown in the list screen. */
public static String describe(String error_code) {
List<String> parts = new ArrayList<>(getFaults(error_code));
List<Integer> columns = getSoldOutColumns(error_code);
if (columns.size() > 0) {
StringBuilder sb = new StringBuilder("품절 (컬럼 ");
for (int i = 0; i < columns.size(); i++) {
if (i > 0)
sb.append(", ");
sb.append(columns.get(i));
}
sb.append(")");
parts.add(sb.toString());
}
if (parts.isEmpty())
return hasRepresentative(error_code) ? "대표이상" : "";
return String.join(", ", parts);
}
}
@@ -24,8 +24,8 @@ public class SMSSender {
private static final Logger logger = LoggerFactory.getLogger(SMSSender.class);
// Munja114 account, issued and authorized through the Munja114 customer center
private static final String REMOTE_ID = "";
private static final String REMOTE_PASS = "";
private static final String REMOTE_ID = "handong3883";
private static final String REMOTE_PASS = "gksehd3885@";
private static final String URL_SMS = "https://www.munja114.co.kr/Remote/RemoteSms.html";
private static final String URL_LMS = "https://www.munja114.co.kr/Remote/RemoteMms.html";
@@ -56,8 +56,9 @@ class AccountController {
String user_id = body.get("user_id");
String email = body.get("email");
Long biz_group_id = _AG.toLong(body.get("biz_group_id"));
Long state = _AG.toLong(body.get("state"));
Map<String, Object> mapResult = accountService.getAccountList(offset, limit, date_start, date_end, is_excel, is_group_access, user_id, email, name, phone, biz_group_id);
Map<String, Object> mapResult = accountService.getAccountList(offset, limit, date_start, date_end, is_excel, is_group_access, user_id, email, name, phone, biz_group_id, state);
if (is_excel) {
List<Map<String, String>> list = (List<Map<String, String>>)mapResult.get("list");
@@ -0,0 +1,46 @@
package com.handong.smartservice.controller.api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import com.handong.smartservice._AG;
import com.handong.smartservice.component.CtResponse;
import com.handong.smartservice.service.DashboardService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Map;
@RestController
@RequestMapping("/api")
class DashboardController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private static final long DEFAULT_DAYS = 7L;
private static final long MAX_DAYS = 31L;
private final DashboardService dashboardService;
public DashboardController(DashboardService dashboardService) {
this.dashboardService = dashboardService;
}
@RequestMapping(value = "/get-dashboard.do", method = RequestMethod.POST)
public CtResponse getDashboard(HttpServletRequest request, HttpServletResponse response, @RequestBody(required = false) Map<String, String> body) {
logger.info("req: " + request.getRequestURI());
CtResponse result = new CtResponse();
Long days = body != null ? _AG.toLong(body.get("days")) : 0L;
if (days == null || days <= 0)
days = DEFAULT_DAYS;
if (days > MAX_DAYS)
days = MAX_DAYS;
result.put("result", dashboardService.getDashboard(days));
return result;
}
}
@@ -0,0 +1,112 @@
package com.handong.smartservice.controller.api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import com.handong.smartservice._AG;
import com.handong.smartservice.component.CtExcelMaker;
import com.handong.smartservice.component.CtResponse;
import com.handong.smartservice.component.ErrorCode;
import com.handong.smartservice.service.DeviceErrorService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api")
class DeviceErrorController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final DeviceErrorService deviceErrorService;
public DeviceErrorController(DeviceErrorService deviceErrorService) {
this.deviceErrorService = deviceErrorService;
}
@RequestMapping(value = "/get-device-error.do", method = RequestMethod.POST)
public CtResponse getDeviceErrorList(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, String> body) {
logger.info("req: " + request.getRequestURI());
CtResponse result = new CtResponse();
Boolean is_excel = _AG.toBoolean(body.get("is_excel"));
Long offset = _AG.toLong(body.get("offset"));
Long limit = _AG.toLong(body.get("limit"));
if (limit > 100)
limit = 100L;
Boolean is_group_access = _AG.toBoolean(body.get("is_group_access"));
String date_start = body.get("date_start");
String date_end = body.get("date_end");
Long biz_group_id = _AG.toLong(body.get("biz_group_id"));
String device_name = body.get("device_name");
String uid1 = body.get("uid1");
Long uid1_type = _AG.toLong(body.get("uid1_type"));
String type = body.get("type");
String error_code = body.get("error_code");
Long error_type = _AG.toLong(body.get("error_type"));
Map<String, Object> mapResult = deviceErrorService.getDeviceErrorList(is_excel, offset, limit, is_group_access, biz_group_id, date_start, date_end,
device_name, uid1, uid1_type, type, error_code, error_type);
if (is_excel) {
List<Map<String, String>> list = (List<Map<String, String>>)mapResult.get("list");
for (Map<String, String> item : list) {
item.replace("reg_time", _AG.timestampToStr(item.get("reg_time")));
}
// The vending machine type and the raw telegram are kept in the DB only, never shown
String[] arrHeader = {"발생시간", "무인기기명", "단말기 TID", "에러유형", "에러내용"};
String[] arrColumn = {"reg_time", "device_name", "uid1", "error_type", "error_desc"};
CtExcelMaker.makeExcelResponse(request, response, "ERROR품절내역목록", arrHeader, arrColumn, list, null);
return null;
}
result.put("result", mapResult);
return result;
}
@RequestMapping(value = "/get-device-error-detail.do", method = RequestMethod.POST)
public CtResponse getDeviceErrorDetail(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, String> body) {
logger.info("req: " + request.getRequestURI());
CtResponse result = new CtResponse();
Long device_error_id = _AG.toLong(body.get("device_error_id"));
if (device_error_id == 0) {
result.setErrCode(ErrorCode.INVALID_PARAMETER);
return result;
}
result.put("result", deviceErrorService.getDeviceErrorDetail(device_error_id));
return result;
}
@RequestMapping(value = "/add-device-error.do", method = RequestMethod.POST)
public CtResponse addDeviceError(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, String> body) {
logger.info("req: " + request.getRequestURI());
CtResponse result = new CtResponse();
String uid1 = body.get("uid1");
Long uid1_type = _AG.toLong(body.get("uid1_type"));
String type = body.get("type");
String error_code = body.get("error_code");
Long error_type = _AG.toLong(body.get("error_type"));
if (_AG.hasText(uid1) == false || uid1_type == null || _AG.hasText(type) == false) {
result.setErrCode(ErrorCode.INVALID_PARAMETER);
return result;
}
result = deviceErrorService.addDeviceError(uid1, uid1_type, type, error_code, error_type);
return result;
}
}
@@ -0,0 +1,44 @@
package com.handong.smartservice.controller.api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import com.handong.smartservice.component.CtResponse;
import com.handong.smartservice.component.SMSSender;
import jakarta.servlet.http.HttpServletRequest;
/**
* TEMPORARY: sends one fixed test message so the Munja114 integration can be verified
* from the sign in screen. The callback, the receiver and the body are fixed here on
* purpose - the endpoint is reachable without a token, so it must not be able to send
* an arbitrary message to an arbitrary number. Delete this class once the test is done.
*/
@RestController
@RequestMapping("/api")
class SmsTestController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private static final String TEST_CALLBACK = "0314263883";
private static final String TEST_PHONE = "01040334076";
private static final String TEST_MESSAGE = "안녕하세요. 테스트입니다.";
@RequestMapping(value = "/send-sms-test.do", method = RequestMethod.POST)
public CtResponse sendSmsTest(HttpServletRequest request) {
logger.info("req: " + request.getRequestURI());
SMSSender.Result sendResult = SMSSender.send(TEST_CALLBACK, TEST_PHONE, TEST_MESSAGE);
logger.info("send-sms-test: " + sendResult);
CtResponse result = new CtResponse();
result.put("code", sendResult.code);
result.put("msg", sendResult.msg);
result.put("sentCount", sendResult.sentCount);
result.put("remainCount", sendResult.remainCount);
result.put("callback", TEST_CALLBACK);
result.put("phone", TEST_PHONE);
return result;
}
}
@@ -74,8 +74,8 @@ class TransactionController {
item.replace("order_time", _AG.timestampToStr(item.get("order_time")));
}
String[] arrHeader = {"거래시간", "단말기 TID", "금액", "결제유형", "승인번호", "컬럼번호", "상품코드", "상품명", "결제서비스업체"};
String[] arrColumn = {"order_time", "uid1", "amount", "type", "approval", "column_no", "code", "goods_name", "pay_vendor"};
String[] arrHeader = {"거래시간", "단말기 TID", "금액", "결제유형", "승인번호", "카드번호", "컬럼번호", "상품코드", "상품명", "결제서비스업체"};
String[] arrColumn = {"order_time", "uid1", "amount", "type", "approval", "card_num", "column_no", "code", "goods_name", "pay_vendor"};
CtExcelMaker.makeExcelResponse(request, response, "거래내역목록", arrHeader, arrColumn, list, null);
return null;
@@ -13,7 +13,7 @@ public interface AccountMapper {
String date_start, String date_end, Long gid, String user_id, String email, String name, String phone, Long biz_group_id);
List<Map<String, Object>> selectAccount2(Boolean isCount, Long offset, Long limit,
String date_start, String date_end, Boolean is_excel, Long gid, String user_id, String email, String name, String phone, Long biz_group_id);
String date_start, String date_end, Boolean is_excel, Long gid, String user_id, String email, String name, String phone, Long biz_group_id, Long state);
int insertAccount(Map<String, Object> params);
@@ -0,0 +1,25 @@
package com.handong.smartservice.mapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
import java.util.Map;
/**
* Read only queries for the dashboard, all limited to a short period.
* is_all == true means the caller is a super admin and sees every group,
* otherwise the rows are limited to biz_group_id and its sub groups.
*/
@Mapper
public interface DashboardMapper {
List<Map<String, Object>> selectNoticeOfPeriod(String date_start, String date_end);
List<Map<String, Object>> selectSalesOfPeriod(Boolean is_all, Long biz_group_id, String date_start, String date_end);
List<Map<String, Object>> selectDeviceErrorOfPeriod(Boolean is_all, Long biz_group_id, String date_start, String date_end);
List<Map<String, Object>> selectAccountOfPeriod(Boolean is_all, Long biz_group_id, String date_start, String date_end);
List<Map<String, Object>> selectGoodsOfPeriod(Boolean is_all, Long biz_group_id, String date_start, String date_end);
}
@@ -0,0 +1,18 @@
package com.handong.smartservice.mapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
import java.util.Map;
@Mapper
public interface DeviceErrorMapper {
List<Map<String, Object>> selectDeviceError(Boolean isCount, Boolean is_excel, Long offset, Long limit, Boolean is_group_access,
Long biz_group_id, String date_start, String date_end, String device_name, String uid1, Long uid1_type, String type,
String error_code, Long error_type);
Map<String, Object> selectDeviceErrorById(Long device_error_id);
int insertDeviceError(Map<String, Object> params);
}
@@ -54,17 +54,17 @@ public class AccountService {
return result;
}
public Map<String, Object> getAccountList(Long offset, Long limit, String date_start, String date_end, Boolean is_excel, Boolean is_group_access, String user_id, String email, String name, String phone, Long biz_group_id) {
public Map<String, Object> getAccountList(Long offset, Long limit, String date_start, String date_end, Boolean is_excel, Boolean is_group_access, String user_id, String email, String name, String phone, Long biz_group_id, Long state) {
Map<String, Object> mapResult = new HashMap<>();
//if (is_group_access) {
List<Map<String, Object>> listMap = (List<Map<String, Object>>)accountMapper.selectAccount2(false, offset, limit,
date_start, date_end, is_excel, 0L, user_id, email, name, phone, biz_group_id);
date_start, date_end, is_excel, 0L, user_id, email, name, phone, biz_group_id, state);
mapResult.put("list", listMap);
Long totalCount = _AG.getNumberFromQuery("COUNT(*)", accountMapper.selectAccount2(true, offset, limit,
date_start, date_end, is_excel, 0L, user_id, email, name, phone, biz_group_id));
date_start, date_end, is_excel, 0L, user_id, email, name, phone, biz_group_id, state));
mapResult.put("totalCount", totalCount);
mapResult.put("offset", offset);
return mapResult;
@@ -150,7 +150,7 @@ public class AccountService {
if (changed == 0) {
result.setErrCode(ErrorCode.QUERY_ERROR);
}
DbLogger.insert(2L, "계정 삭제, id: " + ids, 2L);
DbLogger.insert(2L, "계정 해지, id: " + ids, 2L);
return result;
}
@@ -0,0 +1,50 @@
package com.handong.smartservice.service;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Service;
import com.handong.smartservice.component.Permission;
import com.handong.smartservice.component.UserInfo;
import com.handong.smartservice.mapper.DashboardMapper;
@Service
public class DashboardService {
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private final DashboardMapper dashboardMapper;
public DashboardService(DashboardMapper dashboardMapper) {
this.dashboardMapper = dashboardMapper;
}
/**
* Every widget of the dashboard in one call, limited to the last {@code days} days.
* The scope comes from the signed in account, never from the request.
*/
public Map<String, Object> getDashboard(Long days) {
UserInfo userInfo = UserInfo.getCurr();
Boolean is_all = Permission.PERM_ALL.equals(userInfo.getPermission());
Long biz_group_id = userInfo.getBizGroupId();
LocalDate today = LocalDate.now();
String date_end = today.format(DATE_FORMAT);
String date_start = today.minusDays(days - 1).format(DATE_FORMAT);
Map<String, Object> mapResult = new HashMap<>();
mapResult.put("date_start", date_start);
mapResult.put("date_end", date_end);
mapResult.put("notice_list", dashboardMapper.selectNoticeOfPeriod(date_start, date_end));
mapResult.put("sales_list", dashboardMapper.selectSalesOfPeriod(is_all, biz_group_id, date_start, date_end));
mapResult.put("device_error_list", dashboardMapper.selectDeviceErrorOfPeriod(is_all, biz_group_id, date_start, date_end));
mapResult.put("account_list", dashboardMapper.selectAccountOfPeriod(is_all, biz_group_id, date_start, date_end));
mapResult.put("goods_list", dashboardMapper.selectGoodsOfPeriod(is_all, biz_group_id, date_start, date_end));
return mapResult;
}
}
@@ -0,0 +1,156 @@
package com.handong.smartservice.service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Service;
import com.handong.smartservice._AG;
import com.handong.smartservice.component.CtResponse;
import com.handong.smartservice.component.DeviceErrorCode;
import com.handong.smartservice.mapper.BizGroupMapper;
import com.handong.smartservice.mapper.DeviceErrorMapper;
import com.handong.smartservice.mapper.GoodsMapper;
import com.handong.smartservice.mapper.TerminalMapper;
@Service
public class DeviceErrorService {
private final DeviceErrorMapper deviceErrorMapper;
private final GoodsMapper goodsMapper;
private final BizGroupMapper bizGroupMapper;
private final TerminalMapper terminalMapper;
public DeviceErrorService(DeviceErrorMapper deviceErrorMapper, GoodsMapper goodsMapper, BizGroupMapper bizGroupMapper, TerminalMapper terminalMapper) {
this.deviceErrorMapper = deviceErrorMapper;
this.goodsMapper = goodsMapper;
this.bizGroupMapper = bizGroupMapper;
this.terminalMapper = terminalMapper;
}
public Map<String, Object> getDeviceErrorList(Boolean is_excel, Long offset, Long limit, Boolean is_group_access, Long biz_group_id,
String date_start, String date_end, String device_name, String uid1, Long uid1_type, String type,
String error_code, Long error_type) {
Map<String, Object> mapResult = new HashMap<>();
List<Map<String, Object>> listMap = (List<Map<String, Object>>)deviceErrorMapper.selectDeviceError(false, is_excel, offset, limit, is_group_access,
biz_group_id, date_start, date_end, device_name, uid1, uid1_type, type, error_code, error_type);
// The telegram is kept in the DB only, so the readable summary is built here
for (Map<String, Object> item : listMap)
item.put("error_desc", DeviceErrorCode.describe((String)item.get("error_code")));
mapResult.put("list", listMap);
Long totalCount = _AG.getNumberFromQuery("COUNT(*)", deviceErrorMapper.selectDeviceError(true, is_excel, offset, limit, is_group_access,
biz_group_id, date_start, date_end, device_name, uid1, uid1_type, type, error_code, error_type));
mapResult.put("totalCount", totalCount);
mapResult.put("offset", offset);
return mapResult;
}
/**
* Parses the telegram of one record into a line per fault / sold out column,
* and names the goods that are registered on each sold out column.
*/
public Map<String, Object> getDeviceErrorDetail(Long device_error_id) {
Map<String, Object> mapResult = new HashMap<>();
List<Map<String, Object>> list = new ArrayList<>();
Map<String, Object> mapError = deviceErrorMapper.selectDeviceErrorById(device_error_id);
if (mapError == null) {
mapResult.put("list", list);
return mapResult;
}
String error_code = (String)mapError.get("error_code");
for (String fault : DeviceErrorCode.getFaults(error_code)) {
Map<String, Object> item = new LinkedHashMap<>();
item.put("detail", fault);
item.put("goods_code", null);
item.put("goods_name", null);
item.put("state", DeviceErrorCode.STATE_FAULT);
list.add(item);
}
List<Integer> columns = DeviceErrorCode.getSoldOutColumns(error_code);
if (columns.size() > 0) {
Map<Long, Map<String, Object>> mapGoods = getGoodsByColumn(toLong(mapError.get("device_id")));
for (Integer column : columns) {
Map<String, Object> goods = mapGoods.get(column.longValue());
Map<String, Object> item = new LinkedHashMap<>();
item.put("detail", column + "번 컬럼 품절");
item.put("goods_code", goods != null ? goods.get("code") : null);
item.put("goods_name", goods != null ? goods.get("name") : null);
item.put("state", DeviceErrorCode.STATE_SOLD_OUT);
list.add(item);
}
}
mapResult.put("result_info", mapError);
mapResult.put("list", list);
return mapResult;
}
// device_goods keeps the column number as text ("01", "02", ...), so it is normalized to a number
private Map<Long, Map<String, Object>> getGoodsByColumn(Long device_id) {
Map<Long, Map<String, Object>> mapGoods = new HashMap<>();
if (device_id == 0)
return mapGoods;
List<Map<String, Object>> listGoods = goodsMapper.selectDeviceGoods(device_id, null, null);
if (listGoods == null)
return mapGoods;
for (Map<String, Object> goods : listGoods)
mapGoods.put(_AG.toLong((String)goods.get("column_no")), goods);
return mapGoods;
}
private Long toLong(Object obj) {
return obj instanceof Number ? ((Number)obj).longValue() : 0L;
}
public CtResponse addDeviceError(String uid1, Long uid1_type, String type, String error_code, Long error_type) {
CtResponse result = new CtResponse();
Long biz_group_id = 0L;
Long device_id = 0L;
// The kiosk only knows its own TID, so the group and the device are resolved from it
Map<String, Object> terminal = terminalMapper.selectTerminal3(uid1, uid1_type);
if (terminal != null) {
device_id = (Long)terminal.get("device_id");
Map<String, Object> mapBizGroup = bizGroupMapper.selectBizGroupByDeviceId(device_id);
if (mapBizGroup != null) {
biz_group_id = (Long)mapBizGroup.get("biz_group_id");
}
else {
Long terminal_id = (Long)terminal.get("terminal_id");
Map<String, Object> mapBizGroup2 = bizGroupMapper.selectBizGroupByTerminalId(terminal_id);
if (mapBizGroup2 != null) {
biz_group_id = (Long)mapBizGroup2.get("biz_group_id");
}
}
}
Map<String, Object> params = new HashMap<>();
params.put("uid1", uid1);
params.put("uid1_type", uid1_type);
params.put("type", type);
params.put("error_code", error_code);
params.put("error_type", error_type);
params.put("biz_group_id", biz_group_id);
params.put("device_id", device_id);
deviceErrorMapper.insertDeviceError(params);
return result;
}
}
@@ -73,7 +73,10 @@
</choose>
FROM account AS AC
JOIN group_tree GT ON GT.biz_group_id = AC.biz_group_id
WHERE state != 2
WHERE 1 = 1
<if test='state != null and state != 0'>
AND AC.state = #{state}
</if>
<if test='date_start != null and date_start != ""'>
AND #{date_start} &lt;= DATE(AC.reg_time)
</if>
@@ -96,7 +99,8 @@
AND AC.phone like CONCAT(#{phone}, '%')
</if>
<if test='isCount == false and is_excel == false'>
ORDER BY gid DESC LIMIT #{limit} OFFSET #{offset}
/* the terminated accounts always go last */
ORDER BY (AC.state = 2), AC.gid DESC LIMIT #{limit} OFFSET #{offset}
</if>
</select>
@@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.handong.smartservice.mapper.DashboardMapper">
<sql id="targetGroupCte">
<if test='is_all == false'>
WITH target_group AS (
WITH RECURSIVE group_tree AS (
SELECT
BG1.biz_group_id,
1 AS depth
FROM biz_group BG1
WHERE BG1.state != 2 AND BG1.biz_group_id = #{biz_group_id}
UNION ALL
SELECT
BG2.biz_group_id,
GT.depth + 1
FROM biz_group BG2
INNER JOIN group_tree GT ON BG2.pid = GT.biz_group_id
WHERE BG2.state != 2 AND GT.depth &lt; 10
)
SELECT biz_group_id
FROM group_tree
)
</if>
</sql>
<select id="selectNoticeOfPeriod" resultType="map">
SELECT N.notice_id, N.reg_time, N.title
FROM notice AS N
WHERE N.state != 2
AND #{date_start} &lt;= DATE(N.reg_time) AND DATE(N.reg_time) &lt;= #{date_end}
ORDER BY N.reg_time DESC
</select>
<select id="selectSalesOfPeriod" resultType="map">
<include refid="targetGroupCte" />
SELECT
DATE_FORMAT(T.reg_time, '%Y-%m-%d') AS date,
COUNT(*) AS total_count,
SUM(CASE WHEN T.type IN ('D1','I1','B1','TM1','EB1') THEN 1 ELSE 0 END) AS approval_count,
SUM(CASE WHEN T.type IN ('D4','I4','B4','TM4','EB4') THEN 1 ELSE 0 END) AS cancel_count,
SUM(T.amount) AS total_amount
FROM transactions AS T
WHERE #{date_start} &lt;= DATE(T.reg_time) AND DATE(T.reg_time) &lt;= #{date_end}
<if test='is_all == false'>
AND T.biz_group_id IN ( SELECT biz_group_id FROM target_group )
</if>
GROUP BY DATE_FORMAT(T.reg_time, '%Y-%m-%d')
ORDER BY date DESC
</select>
<select id="selectDeviceErrorOfPeriod" resultType="map">
<include refid="targetGroupCte" />
SELECT
DATE_FORMAT(E.reg_time, '%Y-%m-%d') AS date,
SUM(CASE WHEN E.error_type = 1 THEN 1 ELSE 0 END) AS fault_count,
SUM(CASE WHEN E.error_type = 2 THEN 1 ELSE 0 END) AS sold_out_count,
COUNT(*) AS total_count
FROM device_error AS E
WHERE #{date_start} &lt;= DATE(E.reg_time) AND DATE(E.reg_time) &lt;= #{date_end}
<if test='is_all == false'>
AND E.biz_group_id IN ( SELECT biz_group_id FROM target_group )
</if>
GROUP BY DATE_FORMAT(E.reg_time, '%Y-%m-%d')
ORDER BY date DESC
</select>
<select id="selectAccountOfPeriod" resultType="map">
<include refid="targetGroupCte" />
SELECT A.gid, A.reg_time, A.user_id, A.name, A.nick_name, BG.name AS biz_group_name
FROM account AS A
LEFT JOIN biz_group BG ON BG.biz_group_id = A.biz_group_id
WHERE A.state != 2
AND #{date_start} &lt;= DATE(A.reg_time) AND DATE(A.reg_time) &lt;= #{date_end}
<if test='is_all == false'>
AND A.biz_group_id IN ( SELECT biz_group_id FROM target_group )
</if>
ORDER BY A.reg_time DESC
</select>
<select id="selectGoodsOfPeriod" resultType="map">
<include refid="targetGroupCte" />
SELECT G.goods_id, G.reg_time, G.code, G.name, G.price, BG.name AS biz_group_name
FROM goods AS G
LEFT JOIN biz_group BG ON BG.biz_group_id = G.biz_group_id
WHERE G.state != 2
AND #{date_start} &lt;= DATE(G.reg_time) AND DATE(G.reg_time) &lt;= #{date_end}
<if test='is_all == false'>
AND G.biz_group_id IN ( SELECT biz_group_id FROM target_group )
</if>
ORDER BY G.reg_time DESC
</select>
</mapper>
@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.handong.smartservice.mapper.DeviceErrorMapper">
<select id="selectDeviceError" resultType="map">
<if test='is_group_access == false'>
WITH target_group AS (
WITH RECURSIVE group_tree AS (
SELECT
BG1.biz_group_id,
1 AS depth
FROM biz_group BG1
WHERE BG1.state != 2 AND BG1.biz_group_id = #{biz_group_id}
UNION ALL
SELECT
BG2.biz_group_id,
GT.depth + 1
FROM biz_group BG2
INNER JOIN group_tree GT ON BG2.pid = GT.biz_group_id
WHERE BG2.state != 2 AND GT.depth &lt; 10
)
SELECT biz_group_id
FROM group_tree
)
</if>
SELECT
<choose>
<when test='isCount == true'>
COUNT(*)
</when>
<otherwise>
E.device_error_id, E.reg_time, E.device_id, D.name AS device_name, E.type, E.uid1, E.uid1_type,
E.error_code, E.error_type
</otherwise>
</choose>
FROM device_error AS E
LEFT JOIN device D ON E.device_id = D.device_id
WHERE
<choose>
<when test='is_group_access == false'>
E.biz_group_id IN ( SELECT biz_group_id FROM target_group )
</when>
<otherwise>
E.biz_group_id = #{biz_group_id}
</otherwise>
</choose>
<if test='date_start != null and date_start != ""'>AND #{date_start} &lt;= DATE(E.reg_time)</if>
<if test='date_end != null and date_end != ""'>AND DATE(E.reg_time) &lt;= #{date_end}</if>
<if test='device_name != null and device_name != ""'>AND D.name like CONCAT('%', #{device_name}, '%')</if>
<if test='uid1 != null and uid1 != ""'>AND E.uid1 = #{uid1}</if>
<if test='uid1_type != null and uid1_type != 0'>AND E.uid1_type = #{uid1_type}</if>
<if test='type != null and type != ""'>AND E.type = #{type}</if>
<if test='error_code != null and error_code != ""'>AND E.error_code like CONCAT('%', #{error_code}, '%')</if>
<if test='error_type != null and error_type != 0'>AND E.error_type = #{error_type}</if>
<if test='isCount == false and is_excel == false'>
ORDER BY E.device_error_id DESC LIMIT #{limit} OFFSET #{offset}
</if>
</select>
<select id="selectDeviceErrorById" resultType="map">
SELECT
E.device_error_id, E.reg_time, E.biz_group_id, E.device_id, D.name AS device_name,
E.type, E.uid1, E.uid1_type, E.error_code, E.error_type
FROM device_error AS E
LEFT JOIN device D ON E.device_id = D.device_id
WHERE E.device_error_id = #{device_error_id}
</select>
<insert id="insertDeviceError" parameterType="map">
INSERT INTO device_error (type, biz_group_id, device_id, uid1, uid1_type, error_code, error_type)
VALUES (#{type}, #{biz_group_id}, #{device_id}, #{uid1}, #{uid1_type}, #{error_code}, #{error_type})
</insert>
</mapper>
@@ -63,11 +63,17 @@
COUNT(*)
</when>
<otherwise>
T.reg_time, T.order_time, D.name AS device_name, T.amount, T.type, T.approval, T.uid1, T.pay_name, T.pay_vendor, T.column_no, T.code, T.goods_name, T.pay_unique_num, T.order_time
T.reg_time, T.order_time, D.name AS device_name, T.amount, T.type, T.approval, T.uid1, T.pay_name, T.pay_vendor, T.column_no, T.code, T.goods_name, T.pay_unique_num, T.order_time,
T.card_num, T.rtid,
/* the original approval, shown under a credit cancel row */
ORG.reg_time AS org_reg_time, ORG.order_time AS org_order_time, ORG.type AS org_type, ORG.amount AS org_amount,
ORG.approval AS org_approval, ORG.card_num AS org_card_num, ORG.pay_name AS org_pay_name, ORG.pay_vendor AS org_pay_vendor,
ORG.column_no AS org_column_no, ORG.code AS org_code, ORG.goods_name AS org_goods_name
</otherwise>
</choose>
FROM transactions AS T
JOIN device D ON T.device_id = D.device_id
LEFT JOIN transactions ORG ON ORG.transaction_id = T.rtid
WHERE
<choose>
<when test='is_group_access == false'>