개발환경 변경 및 설명 추가
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
# docker build -t hd1-was:1.0.8 .
|
||||
# docker tag hd1-was:1.0.8 192.168.219.191:19101/hd1-was:1.0.8
|
||||
# docker push 192.168.219.191:19101/hd1-was:1.0.8
|
||||
# or
|
||||
# .\_docker_push.bat 1.0.8
|
||||
|
||||
FROM eclipse-temurin:21-jdk
|
||||
WORKDIR /app
|
||||
COPY ./build/libs/*.jar app.jar
|
||||
EXPOSE 18080
|
||||
ENTRYPOINT ["java", "-jar", "app.jar"]
|
||||
@@ -0,0 +1,16 @@
|
||||
# docker pull 49.165.181.28:19101/hd1-was:1.0.8
|
||||
docker stop hd1-was
|
||||
docker rm hd1-was
|
||||
docker-compose up -d
|
||||
# or
|
||||
# _docker_pull_restart.sh 1.0.8
|
||||
|
||||
services:
|
||||
hd1:
|
||||
image: 49.165.181.28:19101/hd1-was:1.0.8
|
||||
container_name: hd1-was
|
||||
ports:
|
||||
- "28080:18080"
|
||||
environment:
|
||||
- TZ=Asia/Seoul
|
||||
restart: unless-stopped
|
||||
@@ -195,7 +195,7 @@ 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/change-init-account.do") == 0 || // checks the temporary ID and password itself
|
||||
uri.compareTo("/api/add-device-error.do") == 0 ||
|
||||
uri.compareTo("/api/add-transaction.do") == 0) {
|
||||
return true;
|
||||
|
||||
@@ -5,5 +5,11 @@ public class ErrorCode extends CtErrorCode {
|
||||
static public final int INVALID_REFRESH = -16;
|
||||
|
||||
static public final int INVALID_BIZ_REG_NUM = -17;
|
||||
|
||||
static public final int NEED_ACCOUNT_CHANGE = -18; // signed in with a temporary password, the ID and password must be changed first
|
||||
static public final int INVALID_MOBILE = -19;
|
||||
static public final int SMS_SEND_FAILED = -20;
|
||||
static public final int ACCOUNT_ALREADY_EXIST = -21;
|
||||
static public final int INVALID_NEW_ACCOUNT = -22; // the new ID or password breaks the rules
|
||||
//...
|
||||
}
|
||||
|
||||
+14
-6
@@ -10,6 +10,8 @@ import java.time.Duration;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Munja114 (www.munja114.co.kr) SMS/LMS URL integration.
|
||||
@@ -20,12 +22,18 @@ import org.slf4j.LoggerFactory;
|
||||
*
|
||||
* The response body is a pipe separated string: code|msg|nums|cols|etc1|etc2
|
||||
*/
|
||||
@Component
|
||||
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 = "handong3883";
|
||||
private static final String REMOTE_PASS = "gksehd3885@";
|
||||
// Munja114 account, issued and authorized through the Munja114 customer center (sms.remote-id / sms.remote-pass)
|
||||
private final String remoteId;
|
||||
private final String remotePass;
|
||||
|
||||
public SMSSender(@Value("${sms.remote-id}") String remoteId, @Value("${sms.remote-pass}") String remotePass) {
|
||||
this.remoteId = remoteId;
|
||||
this.remotePass = remotePass;
|
||||
}
|
||||
|
||||
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";
|
||||
@@ -101,7 +109,7 @@ public class SMSSender {
|
||||
* @param phone receiver number, comma separated for multiple receivers
|
||||
* @param msg message body, sent as SMS when it fits in 90 EUC-KR bytes, otherwise as LMS
|
||||
*/
|
||||
public static Result send(String callback, String phone, String msg) {
|
||||
public Result send(String callback, String phone, String msg) {
|
||||
if (!hasText(callback) || !hasText(phone) || !hasText(msg)) {
|
||||
logger.warn("send: missing parameter, callback={}, phone={}", callback, phone);
|
||||
return new Result(CODE_INVALID_PARAMETER, "invalid parameter", 0, 0, "");
|
||||
@@ -120,8 +128,8 @@ public class SMSSender {
|
||||
}
|
||||
|
||||
StringBuilder body = new StringBuilder();
|
||||
appendParam(body, "remote_id", REMOTE_ID);
|
||||
appendParam(body, "remote_pass", REMOTE_PASS);
|
||||
appendParam(body, "remote_id", remoteId);
|
||||
appendParam(body, "remote_pass", remotePass);
|
||||
appendParam(body, "remote_num", String.valueOf(receiverCount));
|
||||
appendParam(body, "remote_reserve", "0");
|
||||
appendParam(body, "remote_phone", phoneList);
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.handong.smartservice.component;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/** Temporary password of an issued or reset account, short enough to be typed from a text message. */
|
||||
public class TempPassword {
|
||||
|
||||
// Look-alike characters (0, O, 1, l, I) are left out
|
||||
private static final String LETTERS = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
|
||||
private static final String DIGITS = "23456789";
|
||||
private static final int LENGTH = 8;
|
||||
|
||||
private static final SecureRandom secureRandom = new SecureRandom();
|
||||
|
||||
/** Letters and digits only, always with at least one of each. */
|
||||
public static String create() {
|
||||
String all = LETTERS + DIGITS;
|
||||
|
||||
char[] pw = new char[LENGTH];
|
||||
pw[0] = LETTERS.charAt(secureRandom.nextInt(LETTERS.length()));
|
||||
pw[1] = DIGITS.charAt(secureRandom.nextInt(DIGITS.length()));
|
||||
for (int i = 2; i < LENGTH; i++)
|
||||
pw[i] = all.charAt(secureRandom.nextInt(all.length()));
|
||||
|
||||
// Shuffle so the letter and the digit are not always in front
|
||||
for (int i = LENGTH - 1; i > 0; i--) {
|
||||
int j = secureRandom.nextInt(i + 1);
|
||||
char tmp = pw[i];
|
||||
pw[i] = pw[j];
|
||||
pw[j] = tmp;
|
||||
}
|
||||
|
||||
return new String(pw);
|
||||
}
|
||||
}
|
||||
+10
@@ -36,6 +36,16 @@ class AccountController {
|
||||
this.accountService = accountService;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/reset-account-password.do", method = RequestMethod.POST)
|
||||
public CtResponse resetAccountPassword(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, String> body) {
|
||||
logger.info("req: " + request.getRequestURI());
|
||||
|
||||
Long gid = _AG.toLong(body.get("gid"));
|
||||
String phone = body.get("phone");
|
||||
|
||||
return accountService.resetPassword(gid, phone);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/get-account.do", method = RequestMethod.POST)
|
||||
public CtResponse getAccountList(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, String> body) {
|
||||
logger.info("req: " + request.getRequestURI());
|
||||
|
||||
+41
-1
@@ -18,6 +18,7 @@ import com.handong.smartservice.component.CtResponse;
|
||||
import com.handong.smartservice.component.ErrorCode;
|
||||
import com.handong.smartservice.component.UserInfo;
|
||||
import com.handong.smartservice.service.AccountService;
|
||||
import com.handong.smartservice.service.BizGroupService;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
@@ -48,7 +49,7 @@ class AuthController {
|
||||
public CtResponse signIn(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, String> body) {
|
||||
logger.info("req: " + request.getRequestURI());
|
||||
|
||||
String user_id = body.get("id");
|
||||
String user_id = normalizeUserId(body.get("id"));
|
||||
String user_pw = body.get("pw");
|
||||
|
||||
logger.info("user_id = " + user_id); //TestComment
|
||||
@@ -83,6 +84,16 @@ class AuthController {
|
||||
return result;
|
||||
}
|
||||
|
||||
// An issued account signs in with the temporary password only to change it: no token is given
|
||||
if (((Number)mapAccount.get("state")).longValue() == BizGroupService.ACCOUNT_STATE_INIT) {
|
||||
CtResponse needChange = new CtResponse();
|
||||
needChange.setErrCode(ErrorCode.NEED_ACCOUNT_CHANGE);
|
||||
return needChange;
|
||||
}
|
||||
|
||||
// The account row goes back to the client, so the password hash must not travel with it
|
||||
mapAccount.remove("user_pw");
|
||||
|
||||
//mapAccount.put("sval1", jwtProvider.createAccessToken(gid, user_id, name, permission, biz_group_id));
|
||||
mapAccount.put("sval1", jwtProvider.createAccessToken(gid, _AG.createUserInfoMap(user_id, name, permission, biz_group_id)));
|
||||
String refreshToken = jwtProvider.createRefreshToken(gid);
|
||||
@@ -107,6 +118,28 @@ class AuthController {
|
||||
return result;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/change-init-account.do", method = RequestMethod.POST)
|
||||
public CtResponse changeInitAccount(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, String> body) {
|
||||
logger.info("req: " + request.getRequestURI());
|
||||
|
||||
String user_id = normalizeUserId(body.get("id"));
|
||||
String user_pw = body.get("pw");
|
||||
String new_id = body.get("new_id") == null ? null : body.get("new_id").trim();
|
||||
String new_pw = body.get("new_pw");
|
||||
boolean agree = _AG.toBoolean(body.get("agree"));
|
||||
|
||||
return accountService.changeInitAccount(user_id, user_pw, new_id, new_pw, agree);
|
||||
}
|
||||
|
||||
// An issued ID is the business number, which people often type with dashes
|
||||
private String normalizeUserId(String user_id) {
|
||||
if (user_id == null)
|
||||
return null;
|
||||
|
||||
user_id = user_id.trim();
|
||||
return user_id.matches("^[0-9-]+$") ? user_id.replaceAll("-", "") : user_id;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/sign-out.do", method = RequestMethod.POST)
|
||||
public CtResponse signOut(HttpServletRequest request, HttpServletResponse response,
|
||||
@RequestBody Map<String, String> body) {
|
||||
@@ -155,6 +188,12 @@ class AuthController {
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
// A session must not outlive an account that was put back to the temporary state
|
||||
if (((Number)mapAccount.get("state")).longValue() == BizGroupService.ACCOUNT_STATE_INIT) {
|
||||
result.setErrCode(ErrorCode.NEED_ACCOUNT_CHANGE);
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
String user_id = (String)mapAccount.get("user_id");
|
||||
String name = (String)mapAccount.get("user_id");
|
||||
Long permission = (Long)mapAccount.get("permission");
|
||||
@@ -162,6 +201,7 @@ class AuthController {
|
||||
//String newAccessToken = jwtProvider.createAccessToken(gid, user_id, name, permission, biz_group_id);
|
||||
String newAccessToken = jwtProvider.createAccessToken(gid, _AG.createUserInfoMap(user_id, name, permission, biz_group_id));
|
||||
|
||||
mapAccount.remove("user_pw");
|
||||
mapAccount.put("sval1", newAccessToken);
|
||||
|
||||
return ResponseEntity.ok(result);
|
||||
|
||||
+4
-1
@@ -103,7 +103,10 @@ class BizGroupController {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = bizGroupService.addOrModifyBizGroup(isModify, biz_group_id, pid, top_group_id, name, biz_reg_num, email, phone, ceo, address);
|
||||
// Only a new group can issue an account; the modal checks it by default
|
||||
boolean issue_account = _AG.toBoolean(body.get("issue_account"));
|
||||
|
||||
result = bizGroupService.addOrModifyBizGroup(isModify, biz_group_id, pid, top_group_id, name, biz_reg_num, email, phone, ceo, address, issue_account);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+13
-9
@@ -62,12 +62,10 @@ class DeviceController {
|
||||
|
||||
for (Map<String, String> item : list) {
|
||||
item.replace("reg_time", _AG.timestampToStr(item.get("reg_time")));
|
||||
item.replace("connect_time", _AG.timestampToStr(item.get("connect_time")));
|
||||
item.replace("disconnect_time", _AG.timestampToStr(item.get("disconnect_time")));
|
||||
}
|
||||
|
||||
String[] arrHeader = {"등록일", "그룹", "장치명", "단말기TID", "가동시간", "장애발생시간", "관리자"};
|
||||
String[] arrColumn = {"reg_time", "biz_group_name", "name", "uid1", "connect_time", "disconnect_time", "manager_name"};
|
||||
String[] arrHeader = {"등록일", "그룹", "장치명", "단말기TID", "관리자"};
|
||||
String[] arrColumn = {"reg_time", "biz_group_name", "name", "uid1", "manager_name"};
|
||||
|
||||
CtExcelMaker.makeExcelResponse(request, response, "무인기기목록", arrHeader, arrColumn, list, null);
|
||||
return null;
|
||||
@@ -128,13 +126,19 @@ class DeviceController {
|
||||
public CtResponse configDevice(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, String> body) {
|
||||
logger.info("req: " + request.getRequestURI());
|
||||
|
||||
CtResponse result = new CtResponse();
|
||||
Long device_id = _AG.toLong(body.get("device_id"));
|
||||
|
||||
// Return the service response as is, so its errCode reaches the client
|
||||
return deviceService.configDevice(device_id);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/clear-device-empty.do", method = RequestMethod.POST)
|
||||
public CtResponse clearDeviceEmpty(HttpServletRequest request, HttpServletResponse response, @RequestBody Map<String, String> body) {
|
||||
logger.info("req: " + request.getRequestURI());
|
||||
|
||||
Long device_id = _AG.toLong(body.get("device_id"));
|
||||
|
||||
Map<String, Object> mapResult = deviceService.configDevice(device_id);
|
||||
result.put("result", mapResult);
|
||||
return result;
|
||||
|
||||
return deviceService.clearDeviceEmpty(device_id);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/error-device.do", method = RequestMethod.POST)
|
||||
|
||||
+17
-2
@@ -80,12 +80,27 @@ class DeviceErrorController {
|
||||
CtResponse result = new CtResponse();
|
||||
|
||||
Long device_error_id = _AG.toLong(body.get("device_error_id"));
|
||||
if (device_error_id == 0) {
|
||||
Long device_id = _AG.toLong(body.get("device_id"));
|
||||
|
||||
// Either one record, or (from the device list) the latest sold out record of a device
|
||||
Map<String, Object> mapResult;
|
||||
if (device_error_id != 0) {
|
||||
mapResult = deviceErrorService.getDeviceErrorDetail(device_error_id);
|
||||
}
|
||||
else if (device_id != 0) {
|
||||
mapResult = deviceErrorService.getLatestSoldOutDetail(device_id);
|
||||
}
|
||||
else {
|
||||
result.setErrCode(ErrorCode.INVALID_PARAMETER);
|
||||
return result;
|
||||
}
|
||||
|
||||
result.put("result", deviceErrorService.getDeviceErrorDetail(device_error_id));
|
||||
if (mapResult == null) {
|
||||
result.setErrCode(ErrorCode.PERMISSION_DENIED);
|
||||
return result;
|
||||
}
|
||||
|
||||
result.put("result", mapResult);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -20,4 +20,10 @@ public interface AccountMapper {
|
||||
int updateAccount(Long gid, String user_pw, String name, String phone, String email, Long state, Long biz_group_id, Long permission);
|
||||
|
||||
int changeState(List<Long> ids, int state);
|
||||
|
||||
int countActiveUserId(String user_id, Long exclude_gid);
|
||||
|
||||
int updateInitAccount(Long gid, String user_id, String user_pw);
|
||||
|
||||
int updateResetPassword(Long gid, String user_pw);
|
||||
}
|
||||
|
||||
+4
@@ -14,5 +14,9 @@ public interface DeviceErrorMapper {
|
||||
|
||||
Map<String, Object> selectDeviceErrorById(Long device_error_id);
|
||||
|
||||
Long selectLatestSoldOutErrorId(Long device_id);
|
||||
|
||||
int selectGroupInTree(Long root_group_id, Long biz_group_id);
|
||||
|
||||
int insertDeviceError(Map<String, Object> params);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ public interface DeviceMapper {
|
||||
int updateDevice(Long device_id, Long terminal_id, String name, String uid1, String manager_name, Long gid);
|
||||
|
||||
int updateDeviceTerminalTime(Long device_id, LocalDateTime connect_time, LocalDateTime disconnect_time);
|
||||
|
||||
int updateDeviceEmptyClear(Long device_id);
|
||||
|
||||
int changeStateDevice(List<Long> ids, int state);
|
||||
|
||||
|
||||
+2
@@ -24,5 +24,7 @@ public interface TransactionMapper {
|
||||
|
||||
Map<String, Object> selectTransactionSum(Boolean is_group_access, Long biz_group_id, String date_start, String date_end);
|
||||
|
||||
Long selectOrgTransactionId(String uid1, String approval);
|
||||
|
||||
int insertTransaction(Map<String, Object> params);
|
||||
}
|
||||
|
||||
+101
-1
@@ -14,8 +14,11 @@ import com.handong.smartservice.component.CtResponse;
|
||||
import com.handong.smartservice.component.DbLogger;
|
||||
import com.handong.smartservice.component.ErrorCode;
|
||||
import com.handong.smartservice.component.Permission;
|
||||
import com.handong.smartservice.component.SMSSender;
|
||||
import com.handong.smartservice.component.TempPassword;
|
||||
import com.handong.smartservice.component.UserInfo;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
@@ -30,10 +33,15 @@ public class AccountService {
|
||||
|
||||
private final AccountMapper accountMapper;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
private final SMSSender smsSender;
|
||||
|
||||
public AccountService(AccountMapper accountMapper, PasswordEncoder passwordEncoder) {
|
||||
@Value("${sms.callback}") String smsCallback;
|
||||
@Value("${account.site-url}") String siteUrl;
|
||||
|
||||
public AccountService(AccountMapper accountMapper, PasswordEncoder passwordEncoder, SMSSender smsSender) {
|
||||
this.accountMapper = accountMapper;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
this.smsSender = smsSender;
|
||||
}
|
||||
|
||||
public CtResponse getAccount(Long gid, String user_id) {
|
||||
@@ -139,6 +147,98 @@ public class AccountService {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the temporary ID and password of an issued account (state 6) with the user's own.
|
||||
* The temporary credentials are checked again here, because the caller has no token yet.
|
||||
*/
|
||||
public CtResponse changeInitAccount(String user_id, String user_pw, String new_id, String new_pw, boolean agree) {
|
||||
CtResponse result = new CtResponse();
|
||||
|
||||
// Without the terms of service agreement the account stays initialized, so the site cannot be used
|
||||
if (agree == false) {
|
||||
result.setErrCode(ErrorCode.INVALID_PARAMETER);
|
||||
return result;
|
||||
}
|
||||
|
||||
CtResponse resAccount = getAccount(0L, user_id);
|
||||
Map<String, Object> mapAccount = (Map<String, Object>)resAccount.get("result");
|
||||
|
||||
if (mapAccount == null
|
||||
|| passwordEncoder.matches(user_pw, (String)mapAccount.get("user_pw")) == false
|
||||
|| ((Number)mapAccount.get("state")).longValue() != BizGroupService.ACCOUNT_STATE_INIT) {
|
||||
result.setErrCode(ErrorCode.INVALID_USER);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ID: 4 to 50 letters, digits or . _ -, password: 8 to 50 characters with both a letter and a digit
|
||||
if (new_id == null || new_id.matches("^[A-Za-z0-9._-]{4,50}$") == false
|
||||
|| new_pw == null || new_pw.length() < 8 || new_pw.length() > 50
|
||||
|| new_pw.matches(".*[A-Za-z].*") == false || new_pw.matches(".*[0-9].*") == false
|
||||
|| passwordEncoder.matches(new_pw, (String)mapAccount.get("user_pw"))) {
|
||||
result.setErrCode(ErrorCode.INVALID_NEW_ACCOUNT);
|
||||
return result;
|
||||
}
|
||||
|
||||
Long gid = ((Number)mapAccount.get("gid")).longValue();
|
||||
if (accountMapper.countActiveUserId(new_id, gid) > 0) {
|
||||
result.setErrCode(ErrorCode.ACCOUNT_ALREADY_EXIST);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (accountMapper.updateInitAccount(gid, new_id, passwordEncoder.encode(new_pw)) == 0) {
|
||||
result.setErrCode(ErrorCode.QUERY_ERROR);
|
||||
return result;
|
||||
}
|
||||
DbLogger.insert(2L, "임시계정 정보변경(이용약관 동의), id: " + user_id + " -> " + new_id, gid);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the password with a random one and texts it to the given mobile number.
|
||||
* The account keeps its state, so the new password stays valid until it is changed again.
|
||||
*/
|
||||
public CtResponse resetPassword(Long gid, String phone) {
|
||||
CtResponse result = new CtResponse();
|
||||
|
||||
String mobile = phone == null ? "" : phone.replaceAll("[^0-9]", "");
|
||||
if (gid == 0 || mobile.matches("^01[016789][0-9]{7,8}$") == false) {
|
||||
result.setErrCode(ErrorCode.INVALID_MOBILE);
|
||||
return result;
|
||||
}
|
||||
|
||||
CtResponse resAccount = getAccount(gid, null);
|
||||
Map<String, Object> mapAccount = (Map<String, Object>)resAccount.get("result");
|
||||
if (mapAccount == null) {
|
||||
result.setErrCode(ErrorCode.INVALID_USER);
|
||||
return result;
|
||||
}
|
||||
|
||||
String newPw = TempPassword.create();
|
||||
if (accountMapper.updateResetPassword(gid, passwordEncoder.encode(newPw)) == 0) {
|
||||
result.setErrCode(ErrorCode.QUERY_ERROR);
|
||||
return result;
|
||||
}
|
||||
|
||||
String msg = "[스마트서비스] 비밀번호가 초기화되었습니다.\n"
|
||||
+ "사이트: " + siteUrl + "\n"
|
||||
+ "ID: " + mapAccount.get("user_id") + "\n"
|
||||
+ "비밀번호: " + newPw + "\n"
|
||||
+ "로그인 후 비밀번호를 변경해 주세요.";
|
||||
|
||||
SMSSender.Result sendResult = smsSender.send(smsCallback, mobile, msg);
|
||||
if (sendResult.isSuccess() == false) {
|
||||
result.setErrCode(ErrorCode.SMS_SEND_FAILED);
|
||||
result.put("sms_code", sendResult.code);
|
||||
return result;
|
||||
}
|
||||
|
||||
UserInfo userInfo = UserInfo.getCurr();
|
||||
DbLogger.insert(2L, "비밀번호 초기화, id: " + mapAccount.get("user_id"), userInfo.getGid());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public CtResponse removeAccount(String ids) {
|
||||
CtResponse result = new CtResponse();
|
||||
|
||||
|
||||
+89
-5
@@ -13,8 +13,11 @@ import org.apache.ibatis.jdbc.SQL;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
||||
|
||||
import com.handong.smartservice._AG;
|
||||
import com.handong.smartservice.component.CtResponse;
|
||||
@@ -22,7 +25,10 @@ import com.handong.smartservice.component.DbLogger;
|
||||
import com.handong.smartservice.component.ErrorCode;
|
||||
import com.handong.smartservice.component.Permission;
|
||||
import com.handong.smartservice.component.RcTreeBizGroup;
|
||||
import com.handong.smartservice.component.SMSSender;
|
||||
import com.handong.smartservice.component.TempPassword;
|
||||
import com.handong.smartservice.component.UserInfo;
|
||||
import com.handong.smartservice.mapper.AccountMapper;
|
||||
import com.handong.smartservice.mapper.BizGroupMapper;
|
||||
import com.handong.smartservice.mapper.OperatingHistoryMapper;
|
||||
|
||||
@@ -31,7 +37,16 @@ import com.handong.smartservice.mapper.OperatingHistoryMapper;
|
||||
public class BizGroupService {
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
// Account state of an issued account that still carries the temporary ID and password
|
||||
public static final long ACCOUNT_STATE_INIT = 6L;
|
||||
|
||||
@Autowired BizGroupMapper bizGroupMapper;
|
||||
@Autowired AccountMapper accountMapper;
|
||||
@Autowired PasswordEncoder passwordEncoder;
|
||||
@Autowired SMSSender smsSender;
|
||||
|
||||
@Value("${sms.callback}") String smsCallback;
|
||||
@Value("${account.site-url}") String siteUrl;
|
||||
|
||||
|
||||
public Map<String, Object> getBizGroupList(Long offset, Long limit, String date_start, String date_end,
|
||||
@@ -66,9 +81,29 @@ public class BizGroupService {
|
||||
return mapResult;
|
||||
}
|
||||
|
||||
public CtResponse addOrModifyBizGroup(boolean isModify, Long biz_group_id, Long pid, Long top_group_id, String name, String biz_reg_num, String email, String phone, String ceo, String address) {
|
||||
@Transactional
|
||||
public CtResponse addOrModifyBizGroup(boolean isModify, Long biz_group_id, Long pid, Long top_group_id, String name, String biz_reg_num, String email, String phone, String ceo, String address,
|
||||
boolean issue_account) {
|
||||
CtResponse result = new CtResponse();
|
||||
|
||||
// Everything the issued account needs is checked before the group is written
|
||||
boolean isIssue = !isModify && issue_account;
|
||||
String mobile = phone == null ? "" : phone.replaceAll("[^0-9]", "");
|
||||
if (isIssue) {
|
||||
if (biz_reg_num == null || biz_reg_num.isEmpty()) {
|
||||
result.setErrCode(ErrorCode.INVALID_BIZ_REG_NUM);
|
||||
return result;
|
||||
}
|
||||
if (mobile.matches("^01[016789][0-9]{7,8}$") == false) {
|
||||
result.setErrCode(ErrorCode.INVALID_MOBILE);
|
||||
return result;
|
||||
}
|
||||
if (accountMapper.countActiveUserId(biz_reg_num, 0L) > 0) {
|
||||
result.setErrCode(ErrorCode.ACCOUNT_ALREADY_EXIST);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
//if (bizGroupMapper.selectExistBizGroup(biz_group_id, biz_reg_num) != null) {
|
||||
// result.setErrCode(ErrorCode.ALREADY_EXIST);
|
||||
// return result;
|
||||
@@ -96,16 +131,65 @@ public class BizGroupService {
|
||||
|
||||
if (bizGroupMapper.insertBizGroup(params) == 0) {
|
||||
result.setErrCode(ErrorCode.INVALID_PARAMETER);
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
DbLogger.insert(2L, "사업자그룹 추가, 사업자명: " + name + ", 사업자번호: " + biz_reg_num, 2L);
|
||||
result.put("result", Map.of("biz_group_id", params.get("biz_group_id")));
|
||||
|
||||
if (isIssue) {
|
||||
Long new_biz_group_id = ((Number)params.get("biz_group_id")).longValue();
|
||||
|
||||
// A failed message rolls the group and the account back, so the registration can simply be retried
|
||||
String smsCode = issueAccount(new_biz_group_id, name, biz_reg_num, mobile, ceo);
|
||||
if (smsCode != null) {
|
||||
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
|
||||
result.setErrCode(ErrorCode.SMS_SEND_FAILED);
|
||||
result.put("sms_code", smsCode);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
DbLogger.insert(2L, "사업자그룹 추가, 사업자명: " + name + ", 사업자번호: " + biz_reg_num + (isIssue ? ", 계정발급" : ""), 2L);
|
||||
result.put("result", Map.of("biz_group_id", params.get("biz_group_id")));
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the account of a new business group with a temporary password and texts the
|
||||
* sign in information to the group's mobile number.
|
||||
*
|
||||
* @return null when the message was sent, otherwise the gateway result code
|
||||
*/
|
||||
private String issueAccount(Long biz_group_id, String name, String biz_reg_num, String mobile, String ceo) {
|
||||
String tempPw = TempPassword.create();
|
||||
|
||||
Permission permission = new Permission();
|
||||
permission.setGroup(true);
|
||||
permission.setUid1(true);
|
||||
permission.setCancel(true);
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("user_id", biz_reg_num);
|
||||
params.put("user_pw", passwordEncoder.encode(tempPw));
|
||||
params.put("name", ceo != null && ceo.isEmpty() == false ? ceo : name);
|
||||
params.put("phone", mobile);
|
||||
params.put("email", null);
|
||||
params.put("state", ACCOUNT_STATE_INIT);
|
||||
params.put("biz_group_id", biz_group_id);
|
||||
params.put("permission", permission.get());
|
||||
accountMapper.insertAccount(params);
|
||||
|
||||
String msg = "[스마트서비스] 계정이 발급되었습니다.\n"
|
||||
+ "사이트: " + siteUrl + "\n"
|
||||
+ "ID: " + biz_reg_num + "\n"
|
||||
+ "임시비밀번호: " + tempPw + "\n"
|
||||
+ "로그인 후 아이디와 비밀번호를 변경해 주세요.";
|
||||
|
||||
SMSSender.Result sendResult = smsSender.send(smsCallback, mobile, msg);
|
||||
return sendResult.isSuccess() ? null : sendResult.code;
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public CtResponse removeBizGroup(String ids) {
|
||||
CtResponse result = new CtResponse();
|
||||
|
||||
+21
@@ -11,6 +11,8 @@ 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.component.Permission;
|
||||
import com.handong.smartservice.component.UserInfo;
|
||||
import com.handong.smartservice.mapper.BizGroupMapper;
|
||||
import com.handong.smartservice.mapper.DeviceErrorMapper;
|
||||
import com.handong.smartservice.mapper.GoodsMapper;
|
||||
@@ -66,6 +68,10 @@ public class DeviceErrorService {
|
||||
return mapResult;
|
||||
}
|
||||
|
||||
// null tells the caller the record belongs to a group outside the caller's tree
|
||||
if (canAccessGroup(toLong(mapError.get("biz_group_id"))) == false)
|
||||
return null;
|
||||
|
||||
String error_code = (String)mapError.get("error_code");
|
||||
|
||||
for (String fault : DeviceErrorCode.getFaults(error_code)) {
|
||||
@@ -98,6 +104,21 @@ public class DeviceErrorService {
|
||||
return mapResult;
|
||||
}
|
||||
|
||||
// A super admin sees every group; anyone else only their own group and its descendants
|
||||
private boolean canAccessGroup(Long biz_group_id) {
|
||||
UserInfo userInfo = UserInfo.getCurr();
|
||||
if (Permission.PERM_ALL.equals(userInfo.getPermission()))
|
||||
return true;
|
||||
|
||||
return deviceErrorMapper.selectGroupInTree(userInfo.getBizGroupId(), biz_group_id) > 0;
|
||||
}
|
||||
|
||||
/** Detail of the latest sold out record of a device; an empty list when it has none, null when not allowed */
|
||||
public Map<String, Object> getLatestSoldOutDetail(Long device_id) {
|
||||
Long device_error_id = deviceErrorMapper.selectLatestSoldOutErrorId(device_id);
|
||||
return getDeviceErrorDetail(device_error_id != null ? device_error_id : 0L);
|
||||
}
|
||||
|
||||
// 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<>();
|
||||
|
||||
+14
@@ -215,6 +215,20 @@ public class DeviceService {
|
||||
return result;
|
||||
}
|
||||
|
||||
public CtResponse clearDeviceEmpty(Long device_id) {
|
||||
CtResponse result = new CtResponse();
|
||||
UserInfo userInfo = UserInfo.getCurr();
|
||||
|
||||
int changed = deviceMapper.updateDeviceEmptyClear(device_id);
|
||||
if (changed == 0) {
|
||||
result.setErrCode(ErrorCode.QUERY_ERROR);
|
||||
return result;
|
||||
}
|
||||
DbLogger.insert(2L, "무인기기 품절표시 끄기, device_id: " + device_id, userInfo.getGid());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Map<String, Object> selectDeviceByError(Long biz_group_id) {
|
||||
Map<String, Object> mapResult = new HashMap<>();
|
||||
|
||||
|
||||
+5
@@ -120,6 +120,11 @@ public class TransactionService {
|
||||
params.put("device_id", device_id);
|
||||
|
||||
if (type.compareTo("D4") == 0) {
|
||||
// A credit cancel carries the approval number of its original approval
|
||||
if (approval != null && !approval.isEmpty()) {
|
||||
params.put("rtid", transactionMapper.selectOrgTransactionId(uid1, approval));
|
||||
}
|
||||
|
||||
goodsMapper.updateDeviceGoodsPlusInventory(approval);
|
||||
}
|
||||
else if (goods != null) {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Production overrides. Everything not listed here comes from application.yaml.
|
||||
# Run with: java -jar smartservice.jar --spring.profiles.active=prod
|
||||
# (or SPRING_PROFILES_ACTIVE=prod, or ./gradlew bootRun --args='--spring.profiles.active=prod')
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://PROD_DB_HOST:3306/PROD_DB_NAME?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull
|
||||
username: PROD_DB_USER
|
||||
password: PROD_DB_PASSWORD
|
||||
@@ -14,8 +14,8 @@ spring:
|
||||
port: 6379
|
||||
password: secret
|
||||
datasource:
|
||||
#url: jdbc:mysql://localhost:3306/smartservice?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull
|
||||
url: jdbc:mysql://sensemeka.ddns.net:19106/hdsmartsvc?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull
|
||||
#url: jdbc:mysql://sensemeka.ddns.net:19106/hdsmartsvc?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull
|
||||
url: jdbc:mysql://localhost:3306/hdsmartsvc?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull
|
||||
username: smartsvc2
|
||||
password: Gknehd!@wjdqhxhdtls
|
||||
driver-class-name: com.mysql.jdbc.Driver
|
||||
@@ -30,6 +30,17 @@ mybatis:
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true
|
||||
|
||||
sms:
|
||||
# Munja114 remote account
|
||||
remote-id: "handong3883"
|
||||
remote-pass: "gksehd3885@"
|
||||
# sender number registered with Munja114
|
||||
callback: "0314263883"
|
||||
|
||||
account:
|
||||
# site link texted with an issued account
|
||||
site-url: "http://www.parone.co.kr"
|
||||
|
||||
jwt:
|
||||
secret: c2VjcmV0L12AAsWtleS12ZXJ5LXN232DSJDSKDJWNsllY3VyZS1zZWNyZXQta2V5LXZlcnktc2VjdXJl
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
COUNT(*)
|
||||
</when>
|
||||
<otherwise>
|
||||
AC.gid, AC.user_id, AC.reg_time, AC.user_pw, AC.biz_group_id, GT.name AS biz_group_name, AC.user_pw_time, AC.name, AC.phone, AC.email, AC.state, AC.permission
|
||||
AC.gid, AC.user_id, AC.reg_time, AC.biz_group_id, GT.name AS biz_group_name, AC.user_pw_time, AC.terms_agree_time, AC.name, AC.phone, AC.email, AC.state, AC.permission
|
||||
</otherwise>
|
||||
</choose>
|
||||
FROM account AS AC
|
||||
@@ -141,6 +141,28 @@
|
||||
WHERE gid = #{gid}
|
||||
</update>
|
||||
|
||||
<!-- user_id is not unique in the schema, so every ID assignment checks the accounts that are not terminated -->
|
||||
<select id="countActiveUserId" resultType="int">
|
||||
SELECT COUNT(*)
|
||||
FROM account
|
||||
WHERE state != 2 AND user_id = #{user_id} AND gid != #{exclude_gid}
|
||||
</select>
|
||||
|
||||
<!-- Leaves the initialized state (6): the temporary ID and password are replaced by the user's own,
|
||||
and the terms of service agreement that the same page requires is stamped -->
|
||||
<update id="updateInitAccount">
|
||||
UPDATE account
|
||||
SET user_id = #{user_id}, user_pw = #{user_pw}, user_pw_time = NOW(), terms_agree_time = NOW(), state = 1
|
||||
WHERE gid = #{gid} AND state = 6
|
||||
</update>
|
||||
|
||||
<!-- Password reset: only the password changes, the account keeps its state -->
|
||||
<update id="updateResetPassword">
|
||||
UPDATE account
|
||||
SET user_pw = #{user_pw}, user_pw_time = NOW()
|
||||
WHERE gid = #{gid} AND state != 2
|
||||
</update>
|
||||
|
||||
<update id="changeState">
|
||||
<if test='ids != null and ids.size > 0'>
|
||||
UPDATE account
|
||||
|
||||
@@ -69,6 +69,38 @@
|
||||
WHERE E.device_error_id = #{device_error_id}
|
||||
</select>
|
||||
|
||||
<!-- The latest sold out record (error_type 2) of a device, behind the sold out badge of the device list -->
|
||||
<select id="selectLatestSoldOutErrorId" resultType="java.lang.Long">
|
||||
SELECT device_error_id
|
||||
FROM device_error
|
||||
WHERE device_id = #{device_id} AND error_type = 2
|
||||
ORDER BY device_error_id DESC
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<!-- 1 when biz_group_id is root_group_id or one of its descendants, same walk as the list queries -->
|
||||
<select id="selectGroupInTree" resultType="int">
|
||||
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 = #{root_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 < 10
|
||||
)
|
||||
SELECT COUNT(*)
|
||||
FROM group_tree
|
||||
WHERE biz_group_id = #{biz_group_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})
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
COUNT(*)
|
||||
</when>
|
||||
<otherwise>
|
||||
D.device_id, T.terminal_id, BG.biz_group_id, BG.name AS biz_group_name, D.reg_time, D.name, T.uid1, T.type, D.manager_name, D.state, T.connect_time, T.disconnect_time
|
||||
D.device_id, T.terminal_id, BG.biz_group_id, BG.name AS biz_group_name, D.reg_time, D.name, T.uid1, T.type, D.manager_name, D.state, D.is_empty, T.connect_time, T.disconnect_time
|
||||
</otherwise>
|
||||
</choose>
|
||||
FROM device AS D
|
||||
@@ -89,10 +89,17 @@
|
||||
AND T.uid1 = #{uid1}
|
||||
</if>
|
||||
<if test='conn_state != null and conn_state == "1"'>
|
||||
AND T.connect_time IS NOT NULL AND T.disconnect_time IS NOT NULL AND T.connect_time <= T.disconnect_time
|
||||
AND T.connect_time IS NOT NULL AND (T.disconnect_time IS NULL OR T.disconnect_time < T.connect_time)
|
||||
</if>
|
||||
<if test='conn_state != null and conn_state == "4"'>
|
||||
AND T.connect_time IS NOT NULL AND T.disconnect_time IS NOT NULL AND T.connect_time > T.disconnect_time
|
||||
AND T.connect_time IS NOT NULL AND T.disconnect_time IS NOT NULL AND T.disconnect_time > T.connect_time
|
||||
</if>
|
||||
<!-- Sold out is shown instead of the connection state, so it is its own filter and excluded from the others -->
|
||||
<if test='conn_state != null and (conn_state == "1" or conn_state == "4")'>
|
||||
AND IFNULL(D.is_empty, 0) = 0
|
||||
</if>
|
||||
<if test='conn_state != null and conn_state == "5"'>
|
||||
AND D.is_empty = 1
|
||||
</if>
|
||||
<if test='date_start != null and date_start != ""'>
|
||||
AND #{date_start} <= DATE(D.reg_time)
|
||||
@@ -129,7 +136,7 @@
|
||||
COUNT(*)
|
||||
</when>
|
||||
<otherwise>
|
||||
D.device_id, T.terminal_id, GT.biz_group_id, GT.name AS biz_group_name, D.reg_time, D.name, T.uid1, T.type, D.manager_name, D.state, T.connect_time, T.disconnect_time
|
||||
D.device_id, T.terminal_id, GT.biz_group_id, GT.name AS biz_group_name, D.reg_time, D.name, T.uid1, T.type, D.manager_name, D.state, D.is_empty, T.connect_time, T.disconnect_time
|
||||
</otherwise>
|
||||
</choose>
|
||||
FROM device AS D
|
||||
@@ -144,10 +151,17 @@
|
||||
AND T.uid1 = #{uid1}
|
||||
</if>
|
||||
<if test='conn_state != null and conn_state == "1"'>
|
||||
AND T.connect_time IS NOT NULL AND T.disconnect_time IS NOT NULL AND T.connect_time >= T.disconnect_time
|
||||
AND T.connect_time IS NOT NULL AND (T.disconnect_time IS NULL OR T.disconnect_time < T.connect_time)
|
||||
</if>
|
||||
<if test='conn_state != null and conn_state == "4"'>
|
||||
AND T.connect_time IS NOT NULL AND T.disconnect_time IS NOT NULL AND T.connect_time < T.disconnect_time
|
||||
AND T.connect_time IS NOT NULL AND T.disconnect_time IS NOT NULL AND T.disconnect_time > T.connect_time
|
||||
</if>
|
||||
<!-- Sold out is shown instead of the connection state, so it is its own filter and excluded from the others -->
|
||||
<if test='conn_state != null and (conn_state == "1" or conn_state == "4")'>
|
||||
AND IFNULL(D.is_empty, 0) = 0
|
||||
</if>
|
||||
<if test='conn_state != null and conn_state == "5"'>
|
||||
AND D.is_empty = 1
|
||||
</if>
|
||||
<if test='date_start != null and date_start != ""'>
|
||||
AND #{date_start} <= DATE(D.reg_time)
|
||||
@@ -179,7 +193,7 @@
|
||||
INNER JOIN group_tree gt ON bg.pid = gt.biz_group_id
|
||||
)
|
||||
SELECT
|
||||
D.device_id, T.terminal_id, GT.biz_group_id, GT.name AS biz_group_name, D.reg_time, D.name, T.uid1, T.type, D.manager_name, D.state, T.connect_time, T.disconnect_time
|
||||
D.device_id, T.terminal_id, GT.biz_group_id, GT.name AS biz_group_name, D.reg_time, D.name, T.uid1, T.type, D.manager_name, D.state, D.is_empty, T.connect_time, T.disconnect_time
|
||||
FROM device AS D
|
||||
JOIN device_biz_group AS DBG ON DBG.device_id = D.device_id
|
||||
JOIN group_tree GT ON DBG.biz_group_id = GT.biz_group_id
|
||||
@@ -246,6 +260,12 @@
|
||||
WHERE D.device_id = #{device_id}
|
||||
</update>
|
||||
|
||||
<update id="updateDeviceEmptyClear">
|
||||
UPDATE device
|
||||
SET is_empty = NULL
|
||||
WHERE device_id = #{device_id}
|
||||
</update>
|
||||
|
||||
<update id="changeStateDevice">
|
||||
<if test='ids != null and ids.size > 0'>
|
||||
UPDATE device
|
||||
|
||||
@@ -65,10 +65,8 @@
|
||||
<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.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
|
||||
/* the original approval, used for the cancel column and the cancel receipt of a credit cancel row */
|
||||
ORG.order_time AS org_order_time, ORG.goods_name AS org_goods_name
|
||||
</otherwise>
|
||||
</choose>
|
||||
FROM transactions AS T
|
||||
@@ -388,6 +386,15 @@
|
||||
HAVING card_count != 0 OR cash_count != 0 OR tmoney_count != 0 OR cbee_count != 0
|
||||
</select>
|
||||
|
||||
<!-- The original credit approval of a cancel: same terminal and same approval number, latest one first -->
|
||||
<select id="selectOrgTransactionId" resultType="java.lang.Long">
|
||||
SELECT transaction_id
|
||||
FROM transactions
|
||||
WHERE type = 'D1' AND uid1 = #{uid1} AND approval = #{approval}
|
||||
ORDER BY transaction_id DESC
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<insert id="insertTransaction">
|
||||
INSERT INTO transactions
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
@@ -406,6 +413,7 @@
|
||||
<if test='goods_name != null and goods_name != ""'>goods_name,</if>
|
||||
<if test='price != null and price != 0'>price,</if>
|
||||
<if test='pay_name != null and pay_name != ""'>pay_name,</if>
|
||||
<if test='rtid != null'>rtid,</if>
|
||||
<if test='pay_vendor != null and pay_vendor != ""'>pay_vendor</if>
|
||||
</trim>
|
||||
VALUES
|
||||
@@ -425,6 +433,7 @@
|
||||
<if test='goods_name != null and goods_name != ""'>#{goods_name},</if>
|
||||
<if test='price != null and price != 0'>#{price},</if>
|
||||
<if test='pay_name != null and pay_name != ""'>#{pay_name},</if>
|
||||
<if test='rtid != null'>#{rtid},</if>
|
||||
<if test='pay_vendor != null and pay_vendor != ""'>#{pay_vendor}</if>
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
Reference in New Issue
Block a user