nation 버전 이식
This commit is contained in:
@@ -0,0 +1,683 @@
|
||||
package com.bizcare.agent;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 영업점관리 — billing_react BranchController / BranchGroupController / BranchFee entries 이식.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/agent/homes")
|
||||
@RequiredArgsConstructor
|
||||
class CareBranchController {
|
||||
private static final ZoneId KST = ZoneId.of("Asia/Seoul");
|
||||
private static final DateTimeFormatter DT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
private final EntityManager em;
|
||||
private final PasswordEncoder encoder;
|
||||
|
||||
// ---- 영업점 그룹 ----
|
||||
|
||||
@GetMapping("/branch-groups")
|
||||
@Transactional(readOnly = true)
|
||||
ApiResponse branchGroups(@AuthenticationPrincipal JwtUser u) {
|
||||
List<HomesBranchGroup> list = em.createQuery(
|
||||
"select g from HomesBranchGroup g where g.groupId=:gid order by g.seq asc, g.id asc",
|
||||
HomesBranchGroup.class)
|
||||
.setParameter("gid", u.getGroupId())
|
||||
.getResultList();
|
||||
return ApiResponse.ok(list.stream().map(this::groupMap).toList());
|
||||
}
|
||||
|
||||
@PostMapping("/branch-groups")
|
||||
@Transactional
|
||||
ApiResponse createBranchGroup(@RequestBody Map<String, Object> body, @AuthenticationPrincipal JwtUser u) {
|
||||
String name = str(body.get("name"));
|
||||
if (blank(name)) return ApiResponse.fail("그룹명을 입력하세요.");
|
||||
HomesBranchGroup g = new HomesBranchGroup();
|
||||
g.setGroupId(u.getGroupId());
|
||||
g.setName(name.trim());
|
||||
g.setSeq(body.get("seq") instanceof Number n ? n.intValue() : 0);
|
||||
em.persist(g);
|
||||
return ApiResponse.ok(groupMap(g));
|
||||
}
|
||||
|
||||
// ---- 영업점 목록 / CRUD ----
|
||||
|
||||
@GetMapping("/branches")
|
||||
@Transactional(readOnly = true)
|
||||
ApiResponse branches(@AuthenticationPrincipal JwtUser u) {
|
||||
List<HomesBranch> list = em.createQuery(
|
||||
"select b from HomesBranch b where b.groupId=:gid order by b.id desc",
|
||||
HomesBranch.class)
|
||||
.setParameter("gid", u.getGroupId())
|
||||
.getResultList();
|
||||
Map<Long, String> groupNames = groupNameMap(u.getGroupId());
|
||||
return ApiResponse.ok(list.stream().map(b -> listMap(b, groupNames)).toList());
|
||||
}
|
||||
|
||||
@PostMapping("/branches")
|
||||
@Transactional
|
||||
ApiResponse createBranch(@RequestBody Map<String, Object> body,
|
||||
@RequestParam(defaultValue = "1") int level,
|
||||
@RequestParam(required = false) Long branchGroupId,
|
||||
@AuthenticationPrincipal JwtUser u) {
|
||||
String userid = str(body.get("userid"));
|
||||
String password = str(body.get("password"));
|
||||
String officeName = str(body.get("officeName"));
|
||||
String name = str(body.get("name"));
|
||||
String phone = str(body.get("phone"));
|
||||
String email = str(body.get("email"));
|
||||
if (blank(userid) || blank(password)) return ApiResponse.fail("아이디와 패스워드를 입력하세요.");
|
||||
if (blank(officeName) || blank(name)) return ApiResponse.fail("영업점명과 대표자명을 입력하세요.");
|
||||
if (blank(phone) || blank(email)) return ApiResponse.fail("휴대폰과 이메일을 입력하세요.");
|
||||
if (existsUserid(u.getGroupId(), userid, null)) return ApiResponse.fail("다른사람이 사용중인 아이디입니다.");
|
||||
if (existsOfficeName(u.getGroupId(), officeName, null)) return ApiResponse.fail("다른사람이 사용중인 영업점명입니다.");
|
||||
if (existsEmail(u.getGroupId(), email, null)) return ApiResponse.fail("다른 사람이 사용중인 이메일입니다.");
|
||||
|
||||
HomesBranch b = new HomesBranch();
|
||||
b.setGroupId(u.getGroupId());
|
||||
b.setUserid(userid.trim());
|
||||
b.setPasswordHash(encoder.encode(password));
|
||||
b.setName(name.trim());
|
||||
b.setOfficeName(officeName.trim());
|
||||
b.setTel(str(body.get("tel")));
|
||||
b.setPhone(phone.trim());
|
||||
b.setFax(str(body.get("fax")));
|
||||
b.setEmail(email.trim());
|
||||
b.setZipcode(str(body.get("zipcode")));
|
||||
b.setAddress(str(body.get("address")));
|
||||
b.setAddressDetail(str(body.get("addressDetail")));
|
||||
b.setSido(deriveSido(str(body.get("zipcode")), str(body.get("sido")), str(body.get("address"))));
|
||||
b.setLevel(level);
|
||||
b.setGrantFlag(1); // 관리자 등록 시 승인
|
||||
b.setBranchGroupId(branchGroupId != null ? branchGroupId : longOrNull(body.get("branchGroupId")));
|
||||
b.setIsTax(body.get("isTax") instanceof Number n ? n.intValue() : 1);
|
||||
b.setMemo(str(body.get("memo")));
|
||||
em.persist(b);
|
||||
return ApiResponse.ok(listMap(b, groupNameMap(u.getGroupId())));
|
||||
}
|
||||
|
||||
@GetMapping("/branches/{id}/detail")
|
||||
@Transactional(readOnly = true)
|
||||
ApiResponse branchDetail(@PathVariable Long id, @AuthenticationPrincipal JwtUser u) {
|
||||
HomesBranch b = findBranch(id, u);
|
||||
if (b == null) return ApiResponse.fail("영업점을 찾을 수 없습니다.");
|
||||
return ApiResponse.ok(detailMap(b));
|
||||
}
|
||||
|
||||
@PutMapping("/branches/{id}/detail")
|
||||
@Transactional
|
||||
ApiResponse updateBranchDetail(@PathVariable Long id, @RequestBody Map<String, Object> body,
|
||||
@AuthenticationPrincipal JwtUser u) {
|
||||
HomesBranch b = findBranch(id, u);
|
||||
if (b == null) return ApiResponse.fail("영업점을 찾을 수 없습니다.");
|
||||
|
||||
String officeName = str(body.get("officeName"));
|
||||
String email = str(body.get("email"));
|
||||
String name = str(body.get("name"));
|
||||
if (blank(officeName) || blank(name)) return ApiResponse.fail("영업점명과 이름을 입력하세요.");
|
||||
if (existsOfficeName(u.getGroupId(), officeName, id)) return ApiResponse.fail("다른사람이 사용중인 영업점명입니다.");
|
||||
if (!blank(email) && existsEmail(u.getGroupId(), email, id)) return ApiResponse.fail("다른 사람이 사용중인 이메일입니다.");
|
||||
|
||||
String password = str(body.get("password"));
|
||||
String passwordConfirmation = str(body.get("passwordConfirmation"));
|
||||
if (!blank(password)) {
|
||||
if (!password.equals(passwordConfirmation)) return ApiResponse.fail("패스워드 확인이 일치하지 않습니다.");
|
||||
b.setPasswordHash(encoder.encode(password));
|
||||
}
|
||||
|
||||
Long oldGroupId = b.getBranchGroupId();
|
||||
Long newGroupId = longOrNull(body.get("branchGroupId"));
|
||||
boolean keepFee = Boolean.TRUE.equals(body.get("keepFee"))
|
||||
|| "true".equalsIgnoreCase(String.valueOf(body.get("keepFee")));
|
||||
|
||||
b.setName(name.trim());
|
||||
b.setOfficeName(officeName.trim());
|
||||
b.setTel(str(body.get("tel")));
|
||||
b.setPhone(str(body.get("phone")));
|
||||
b.setFax(str(body.get("fax")));
|
||||
b.setEmail(email);
|
||||
b.setZipcode(str(body.get("zipcode")));
|
||||
b.setAddress(str(body.get("address")));
|
||||
b.setAddressDetail(str(body.get("addressDetail")));
|
||||
b.setSido(deriveSido(str(body.get("zipcode")), str(body.get("sido")), str(body.get("address"))));
|
||||
if (body.get("level") instanceof Number n) b.setLevel(n.intValue());
|
||||
b.setBranchGroupId(newGroupId);
|
||||
b.setCenterName(str(body.get("centerName")));
|
||||
if (blank(b.getCenterName()) && body.get("centerId") != null) {
|
||||
// centerId 호환: 숫자면 무시, 문자열이면 이름
|
||||
b.setCenterName(str(body.get("centerId")));
|
||||
}
|
||||
|
||||
boolean isPersonal = Boolean.TRUE.equals(body.get("isPersonal"))
|
||||
|| "true".equalsIgnoreCase(String.valueOf(body.get("isPersonal")));
|
||||
b.setHasBusinessLicense(!isPersonal);
|
||||
b.setLicenseNumber(isPersonal ? null : str(body.get("licenseNumber")));
|
||||
b.setLicenseType(isPersonal ? null : str(body.get("licenseType")));
|
||||
b.setLicenseItem(isPersonal ? null : str(body.get("licenseItem")));
|
||||
|
||||
b.setAccountBank(str(body.get("accountBank")));
|
||||
b.setAccountNumber(str(body.get("accountNumber")));
|
||||
boolean accountNameIsName = Boolean.TRUE.equals(body.get("accountNameIsName"))
|
||||
|| "true".equalsIgnoreCase(String.valueOf(body.get("accountNameIsName")));
|
||||
b.setAccountName(accountNameIsName ? b.getName() : str(body.get("accountName")));
|
||||
|
||||
b.setContactPhone(str(body.get("contactPhone")));
|
||||
b.setContactNateon(str(body.get("contactNateon")));
|
||||
if (body.get("acceptPhone") instanceof Number n) b.setAcceptPhone(n.intValue());
|
||||
if (body.get("acceptNateon") instanceof Number n) b.setAcceptNateon(n.intValue());
|
||||
if (body.get("isTax") instanceof Number n) b.setIsTax(n.intValue());
|
||||
b.setMemo(str(body.get("memo")));
|
||||
b.setAdminMemo(str(body.get("adminMemo")));
|
||||
b.setNotifyPhonesJson(toNotifyJson(body.get("notifyPhones")));
|
||||
|
||||
b.setPermissionOrderDateUpdate(bool(body.get("permissionOrderDateUpdate")));
|
||||
b.setPermissionCalculate(bool(body.get("permissionCalculate")));
|
||||
b.setPermissionConfig(bool(body.get("permissionConfig")));
|
||||
b.setPermissionExcelDownload(bool(body.get("permissionExcelDownload")));
|
||||
b.setPermissionChart(bool(body.get("permissionChart")));
|
||||
|
||||
// keepFee=false 이고 그룹이 바뀌면 개별 수수료는 유지, 그룹 매핑은 이름만 바뀌므로 별도 처리 없음
|
||||
if (!keepFee && !Objects.equals(oldGroupId, newGroupId) && newGroupId != null) {
|
||||
HomesBranchGroup ng = em.find(HomesBranchGroup.class, newGroupId);
|
||||
if (ng != null && Objects.equals(ng.getGroupId(), u.getGroupId())) {
|
||||
// 그룹 수수료는 branchGroupName 문자열 키 — 접수의 branchGroup 과 맞추는 용도만
|
||||
// (실제 접수 일괄 갱신은 범위 외)
|
||||
}
|
||||
}
|
||||
|
||||
return ApiResponse.ok(detailMap(b));
|
||||
}
|
||||
|
||||
@PostMapping("/branches/{id}/grant/{grant}")
|
||||
@Transactional
|
||||
ApiResponse setGrant(@PathVariable Long id, @PathVariable int grant, @AuthenticationPrincipal JwtUser u) {
|
||||
HomesBranch b = findBranch(id, u);
|
||||
if (b == null) return ApiResponse.fail("영업점을 찾을 수 없습니다.");
|
||||
if (grant != 0 && grant != 1) return ApiResponse.fail("승인값은 0 또는 1이어야 합니다.");
|
||||
b.setGrantFlag(grant);
|
||||
return ApiResponse.ok(null);
|
||||
}
|
||||
|
||||
@DeleteMapping("/branches/{id}")
|
||||
@Transactional
|
||||
ApiResponse deleteBranch(@PathVariable Long id, @AuthenticationPrincipal JwtUser u) {
|
||||
HomesBranch b = findBranch(id, u);
|
||||
if (b == null) return ApiResponse.fail("영업점을 찾을 수 없습니다.");
|
||||
em.remove(b);
|
||||
return ApiResponse.ok(null);
|
||||
}
|
||||
|
||||
/** 영업점 수수료 목록 (개별 + 소속 그룹) — billing GET /branch-fee/branch/{id}/entries */
|
||||
@GetMapping("/branches/{id}/fees")
|
||||
@Transactional(readOnly = true)
|
||||
ApiResponse branchFees(@PathVariable Long id, @AuthenticationPrincipal JwtUser u) {
|
||||
HomesBranch b = findBranch(id, u);
|
||||
if (b == null) return ApiResponse.fail("영업점을 찾을 수 없습니다.");
|
||||
|
||||
List<Map<String, Object>> entries = new ArrayList<>();
|
||||
List<HomesBranchFee> alone = em.createQuery(
|
||||
"select f from HomesBranchFee f where f.groupId=:gid and f.feeType='alone' and f.branchName=:name",
|
||||
HomesBranchFee.class)
|
||||
.setParameter("gid", u.getGroupId())
|
||||
.setParameter("name", b.getOfficeName())
|
||||
.getResultList();
|
||||
for (HomesBranchFee f : alone) {
|
||||
entries.add(feeEntryMap(f, "alone"));
|
||||
}
|
||||
|
||||
if (b.getBranchGroupId() != null) {
|
||||
HomesBranchGroup g = em.find(HomesBranchGroup.class, b.getBranchGroupId());
|
||||
if (g != null && Objects.equals(g.getGroupId(), u.getGroupId())) {
|
||||
List<HomesBranchFee> groupFees = em.createQuery(
|
||||
"select f from HomesBranchFee f where f.groupId=:gid and f.feeType='group' and f.branchGroupName=:name",
|
||||
HomesBranchFee.class)
|
||||
.setParameter("gid", u.getGroupId())
|
||||
.setParameter("name", g.getName())
|
||||
.getResultList();
|
||||
for (HomesBranchFee f : groupFees) {
|
||||
entries.add(feeEntryMap(f, "group"));
|
||||
}
|
||||
}
|
||||
}
|
||||
// 적용일 내림차순, 동일일이면 개별(alone) 우선
|
||||
entries.sort((a, b2) -> {
|
||||
String sa = String.valueOf(a.get("startDate") == null ? "" : a.get("startDate"));
|
||||
String sb = String.valueOf(b2.get("startDate") == null ? "" : b2.get("startDate"));
|
||||
int c = sb.compareTo(sa);
|
||||
if (c != 0) return c;
|
||||
int pa = "alone".equals(a.get("type")) ? 0 : 1;
|
||||
int pb = "alone".equals(b2.get("type")) ? 0 : 1;
|
||||
return Integer.compare(pa, pb);
|
||||
});
|
||||
return ApiResponse.ok(entries);
|
||||
}
|
||||
|
||||
/** 수수료 상세 — billing branch-fee/{id}/read/{type} */
|
||||
@GetMapping("/branch-fees/{feeId}")
|
||||
@Transactional(readOnly = true)
|
||||
ApiResponse feeDetail(@PathVariable Long feeId,
|
||||
@RequestParam(defaultValue = "alone") String type,
|
||||
@AuthenticationPrincipal JwtUser u) {
|
||||
HomesBranchFee f = em.find(HomesBranchFee.class, feeId);
|
||||
if (f == null || !Objects.equals(f.getGroupId(), u.getGroupId())) {
|
||||
return ApiResponse.fail("수수료를 찾을 수 없습니다.");
|
||||
}
|
||||
String want = "group".equalsIgnoreCase(type) ? "group" : "alone";
|
||||
if (!want.equals(f.getFeeType())) {
|
||||
return ApiResponse.fail("수수료 종류가 일치하지 않습니다.");
|
||||
}
|
||||
return ApiResponse.ok(feeDetailMap(f));
|
||||
}
|
||||
|
||||
/** 개별 수수료 등록 */
|
||||
@PostMapping("/branches/{id}/fees")
|
||||
@Transactional
|
||||
ApiResponse createAloneFee(@PathVariable Long id, @RequestBody Map<String, Object> body,
|
||||
@AuthenticationPrincipal JwtUser u) {
|
||||
HomesBranch b = findBranch(id, u);
|
||||
if (b == null) return ApiResponse.fail("영업점을 찾을 수 없습니다.");
|
||||
String carrier = str(body.get("carrier"));
|
||||
if (blank(carrier)) return ApiResponse.fail("통신사를 선택하세요.");
|
||||
LocalDateTime start = parseDateTime(body.get("startDate"));
|
||||
if (start == null) return ApiResponse.fail("적용일을 입력하세요.");
|
||||
if (existsAloneFee(u.getGroupId(), b.getOfficeName(), carrier, start, null)) {
|
||||
return ApiResponse.fail("이미 등록되어 있는 적용일입니다.");
|
||||
}
|
||||
HomesBranchFee fee = new HomesBranchFee();
|
||||
fee.setGroupId(u.getGroupId());
|
||||
fee.setFeeType("alone");
|
||||
fee.setBranchName(b.getOfficeName());
|
||||
if (b.getBranchGroupId() != null) {
|
||||
HomesBranchGroup g = em.find(HomesBranchGroup.class, b.getBranchGroupId());
|
||||
if (g != null) fee.setBranchGroupName(g.getName());
|
||||
}
|
||||
fee.setCarrier(carrier);
|
||||
fee.setStartDate(start);
|
||||
fee.setMemo(str(body.get("memo")));
|
||||
em.persist(fee);
|
||||
em.flush();
|
||||
replaceProducts(fee.getId(), u.getGroupId(), body.get("products"));
|
||||
return ApiResponse.ok(feeDetailMap(fee));
|
||||
}
|
||||
|
||||
/** 개별 수수료 수정 — 그룹은 거부 */
|
||||
@PutMapping("/branch-fees/{feeId}")
|
||||
@Transactional
|
||||
ApiResponse updateAloneFee(@PathVariable Long feeId, @RequestBody Map<String, Object> body,
|
||||
@AuthenticationPrincipal JwtUser u) {
|
||||
HomesBranchFee f = em.find(HomesBranchFee.class, feeId);
|
||||
if (f == null || !Objects.equals(f.getGroupId(), u.getGroupId())) {
|
||||
return ApiResponse.fail("수수료를 찾을 수 없습니다.");
|
||||
}
|
||||
if (!"alone".equals(f.getFeeType())) {
|
||||
return ApiResponse.fail("그룹 수수료는 여기서 수정할 수 없습니다.");
|
||||
}
|
||||
LocalDateTime start = parseDateTime(body.get("startDate"));
|
||||
if (start == null) return ApiResponse.fail("적용일을 입력하세요.");
|
||||
String carrier = blank(str(body.get("carrier"))) ? f.getCarrier() : str(body.get("carrier"));
|
||||
if (existsAloneFee(u.getGroupId(), f.getBranchName(), carrier, start, feeId)) {
|
||||
return ApiResponse.fail("이미 등록되어 있는 적용일입니다.");
|
||||
}
|
||||
f.setCarrier(carrier);
|
||||
f.setStartDate(start);
|
||||
f.setMemo(str(body.get("memo")));
|
||||
if (body.containsKey("file1")) f.setFile1(str(body.get("file1")));
|
||||
if (body.containsKey("file2")) f.setFile2(str(body.get("file2")));
|
||||
if (body.containsKey("file3")) f.setFile3(str(body.get("file3")));
|
||||
if (body.containsKey("file4")) f.setFile4(str(body.get("file4")));
|
||||
if (body.containsKey("file5")) f.setFile5(str(body.get("file5")));
|
||||
replaceProducts(feeId, u.getGroupId(), body.get("products"));
|
||||
return ApiResponse.ok(feeDetailMap(f));
|
||||
}
|
||||
|
||||
@DeleteMapping("/branch-fees/{feeId}")
|
||||
@Transactional
|
||||
ApiResponse deleteAloneFee(@PathVariable Long feeId, @AuthenticationPrincipal JwtUser u) {
|
||||
HomesBranchFee f = em.find(HomesBranchFee.class, feeId);
|
||||
if (f == null || !Objects.equals(f.getGroupId(), u.getGroupId())) {
|
||||
return ApiResponse.fail("수수료를 찾을 수 없습니다.");
|
||||
}
|
||||
if (!"alone".equals(f.getFeeType())) {
|
||||
return ApiResponse.fail("그룹 수수료는 여기서 삭제할 수 없습니다.");
|
||||
}
|
||||
em.createQuery("delete from HomesBranchFeeProduct p where p.feeId=:fid and p.groupId=:gid")
|
||||
.setParameter("fid", feeId)
|
||||
.setParameter("gid", u.getGroupId())
|
||||
.executeUpdate();
|
||||
em.remove(f);
|
||||
return ApiResponse.ok(null);
|
||||
}
|
||||
|
||||
/** 등록 폼용 기본 상품 템플릿 (시드/기존 수수료 상품명 재사용) */
|
||||
@GetMapping("/branch-fee-product-templates")
|
||||
@Transactional(readOnly = true)
|
||||
ApiResponse productTemplates(@RequestParam(required = false) String carrier,
|
||||
@AuthenticationPrincipal JwtUser u) {
|
||||
List<HomesBranchFeeProduct> samples = em.createQuery(
|
||||
"select p from HomesBranchFeeProduct p where p.groupId=:gid order by p.id asc",
|
||||
HomesBranchFeeProduct.class)
|
||||
.setParameter("gid", u.getGroupId())
|
||||
.setMaxResults(40)
|
||||
.getResultList();
|
||||
LinkedHashMap<String, Map<String, Object>> uniq = new LinkedHashMap<>();
|
||||
for (HomesBranchFeeProduct p : samples) {
|
||||
String key = p.getProductType() + "|" + p.getProductName();
|
||||
if (uniq.containsKey(key)) continue;
|
||||
Map<String, Object> m = new LinkedHashMap<>();
|
||||
m.put("productType", p.getProductType());
|
||||
m.put("productName", p.getProductName());
|
||||
m.put("fee", 0);
|
||||
uniq.put(key, m);
|
||||
}
|
||||
if (uniq.isEmpty()) {
|
||||
Object[][] defaults = {
|
||||
{"e01", "기가인터넷 1G"}, {"e01", "안심 인터넷"},
|
||||
{"e03", "B tv 프리미엄"}, {"e02", "집전화 스마트"}, {"e04", "기타"},
|
||||
};
|
||||
for (Object[] d : defaults) {
|
||||
Map<String, Object> m = new LinkedHashMap<>();
|
||||
m.put("productType", d[0]);
|
||||
m.put("productName", d[1]);
|
||||
m.put("fee", 0);
|
||||
uniq.put(d[0] + "|" + d[1], m);
|
||||
}
|
||||
}
|
||||
return ApiResponse.ok(new ArrayList<>(uniq.values()));
|
||||
}
|
||||
|
||||
/** 입력처(센터) 후보 — 레벨5 영업점 + 접수 processor distinct */
|
||||
@GetMapping("/branch-centers")
|
||||
@Transactional(readOnly = true)
|
||||
ApiResponse centers(@AuthenticationPrincipal JwtUser u) {
|
||||
LinkedHashSet<String> names = new LinkedHashSet<>();
|
||||
em.createQuery(
|
||||
"select b.officeName from HomesBranch b where b.groupId=:gid and b.level=5 and b.officeName is not null",
|
||||
String.class)
|
||||
.setParameter("gid", u.getGroupId())
|
||||
.getResultList()
|
||||
.forEach(names::add);
|
||||
em.createQuery(
|
||||
"select distinct r.processor from HomesReception r where r.groupId=:gid and r.processor is not null and r.processor<>''",
|
||||
String.class)
|
||||
.setParameter("gid", u.getGroupId())
|
||||
.getResultList()
|
||||
.forEach(names::add);
|
||||
List<Map<String, Object>> out = new ArrayList<>();
|
||||
int i = 1;
|
||||
for (String n : names) {
|
||||
Map<String, Object> m = new LinkedHashMap<>();
|
||||
m.put("id", i++);
|
||||
m.put("name", n);
|
||||
out.add(m);
|
||||
}
|
||||
return ApiResponse.ok(out);
|
||||
}
|
||||
|
||||
// ---- helpers ----
|
||||
|
||||
private void replaceProducts(Long feeId, String groupId, Object productsRaw) {
|
||||
em.createQuery("delete from HomesBranchFeeProduct p where p.feeId=:fid and p.groupId=:gid")
|
||||
.setParameter("fid", feeId)
|
||||
.setParameter("gid", groupId)
|
||||
.executeUpdate();
|
||||
if (!(productsRaw instanceof List<?> list)) return;
|
||||
for (Object o : list) {
|
||||
if (!(o instanceof Map<?, ?> m)) continue;
|
||||
String productType = str(m.get("productType"));
|
||||
String productName = str(m.get("productName"));
|
||||
if (blank(productName)) continue;
|
||||
HomesBranchFeeProduct p = new HomesBranchFeeProduct();
|
||||
p.setGroupId(groupId);
|
||||
p.setFeeId(feeId);
|
||||
p.setProductType(blank(productType) ? "e01" : productType);
|
||||
p.setProductName(productName);
|
||||
Object feeObj = m.get("fee");
|
||||
int fee = feeObj instanceof Number n ? n.intValue() : 0;
|
||||
try {
|
||||
if (!(feeObj instanceof Number) && feeObj != null && !String.valueOf(feeObj).isBlank()) {
|
||||
fee = Integer.parseInt(String.valueOf(feeObj).replace(",", "").replace("원", "").trim());
|
||||
}
|
||||
} catch (Exception ignored) { /* keep 0 */ }
|
||||
p.setFee(fee);
|
||||
em.persist(p);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean existsAloneFee(String gid, String branchName, String carrier, LocalDateTime start, Long excludeId) {
|
||||
String jpql = "select count(f) from HomesBranchFee f where f.groupId=:gid and f.feeType='alone'"
|
||||
+ " and f.branchName=:name and f.carrier=:c and f.startDate=:sd"
|
||||
+ (excludeId != null ? " and f.id<>:id" : "");
|
||||
var q = em.createQuery(jpql, Long.class)
|
||||
.setParameter("gid", gid)
|
||||
.setParameter("name", branchName)
|
||||
.setParameter("c", carrier)
|
||||
.setParameter("sd", start);
|
||||
if (excludeId != null) q.setParameter("id", excludeId);
|
||||
return q.getSingleResult() > 0;
|
||||
}
|
||||
|
||||
private Map<String, Object> feeDetailMap(HomesBranchFee f) {
|
||||
List<HomesBranchFeeProduct> products = em.createQuery(
|
||||
"select p from HomesBranchFeeProduct p where p.feeId=:fid and p.groupId=:gid order by p.productType, p.id",
|
||||
HomesBranchFeeProduct.class)
|
||||
.setParameter("fid", f.getId())
|
||||
.setParameter("gid", f.getGroupId())
|
||||
.getResultList();
|
||||
Map<String, Object> fee = new LinkedHashMap<>();
|
||||
fee.put("id", f.getId());
|
||||
fee.put("type", f.getFeeType());
|
||||
fee.put("branchName", f.getBranchName());
|
||||
fee.put("branchGroupName", f.getBranchGroupName());
|
||||
fee.put("carrier", f.getCarrier());
|
||||
fee.put("ispName", f.getCarrier());
|
||||
fee.put("startDate", f.getStartDate() == null ? null : DT.format(f.getStartDate()));
|
||||
fee.put("memo", f.getMemo());
|
||||
fee.put("file1", f.getFile1());
|
||||
fee.put("file2", f.getFile2());
|
||||
fee.put("file3", f.getFile3());
|
||||
fee.put("file4", f.getFile4());
|
||||
fee.put("file5", f.getFile5());
|
||||
fee.put("source", String.valueOf(f.getId()));
|
||||
|
||||
List<Map<String, Object>> productMaps = new ArrayList<>();
|
||||
for (HomesBranchFeeProduct p : products) {
|
||||
Map<String, Object> pm = new LinkedHashMap<>();
|
||||
pm.put("id", p.getId());
|
||||
pm.put("productType", p.getProductType());
|
||||
pm.put("productName", p.getProductName());
|
||||
pm.put("fee", p.getFee() == null ? 0 : p.getFee());
|
||||
productMaps.add(pm);
|
||||
}
|
||||
Map<String, Object> out = new LinkedHashMap<>();
|
||||
out.put("fee", fee);
|
||||
out.put("products", productMaps);
|
||||
return out;
|
||||
}
|
||||
|
||||
private static LocalDateTime parseDateTime(Object raw) {
|
||||
if (raw == null) return null;
|
||||
String s = String.valueOf(raw).trim().replace('T', ' ');
|
||||
if (s.isEmpty()) return null;
|
||||
try {
|
||||
if (s.length() == 10) return LocalDateTime.parse(s + " 00:00:00", DT);
|
||||
if (s.length() >= 19) return LocalDateTime.parse(s.substring(0, 19), DT);
|
||||
return LocalDateTime.parse(s, DT);
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
return LocalDateTime.parse(s.substring(0, 10) + "T00:00:00");
|
||||
} catch (Exception e2) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private HomesBranch findBranch(Long id, JwtUser u) {
|
||||
HomesBranch b = em.find(HomesBranch.class, id);
|
||||
if (b == null || !Objects.equals(b.getGroupId(), u.getGroupId())) return null;
|
||||
return b;
|
||||
}
|
||||
|
||||
private Map<Long, String> groupNameMap(String groupId) {
|
||||
return em.createQuery(
|
||||
"select g from HomesBranchGroup g where g.groupId=:gid", HomesBranchGroup.class)
|
||||
.setParameter("gid", groupId)
|
||||
.getResultList()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(HomesBranchGroup::getId, HomesBranchGroup::getName, (a, b) -> a));
|
||||
}
|
||||
|
||||
private boolean existsUserid(String gid, String userid, Long excludeId) {
|
||||
String jpql = "select count(b) from HomesBranch b where b.groupId=:gid and b.userid=:uid"
|
||||
+ (excludeId != null ? " and b.id<>:id" : "");
|
||||
var q = em.createQuery(jpql, Long.class).setParameter("gid", gid).setParameter("uid", userid.trim());
|
||||
if (excludeId != null) q.setParameter("id", excludeId);
|
||||
return q.getSingleResult() > 0;
|
||||
}
|
||||
|
||||
private boolean existsOfficeName(String gid, String officeName, Long excludeId) {
|
||||
String jpql = "select count(b) from HomesBranch b where b.groupId=:gid and b.officeName=:n"
|
||||
+ (excludeId != null ? " and b.id<>:id" : "");
|
||||
var q = em.createQuery(jpql, Long.class).setParameter("gid", gid).setParameter("n", officeName.trim());
|
||||
if (excludeId != null) q.setParameter("id", excludeId);
|
||||
return q.getSingleResult() > 0;
|
||||
}
|
||||
|
||||
private boolean existsEmail(String gid, String email, Long excludeId) {
|
||||
String jpql = "select count(b) from HomesBranch b where b.groupId=:gid and b.email=:e"
|
||||
+ (excludeId != null ? " and b.id<>:id" : "");
|
||||
var q = em.createQuery(jpql, Long.class).setParameter("gid", gid).setParameter("e", email.trim());
|
||||
if (excludeId != null) q.setParameter("id", excludeId);
|
||||
return q.getSingleResult() > 0;
|
||||
}
|
||||
|
||||
private Map<String, Object> groupMap(HomesBranchGroup g) {
|
||||
Map<String, Object> m = new LinkedHashMap<>();
|
||||
m.put("id", g.getId());
|
||||
m.put("name", g.getName());
|
||||
m.put("seq", g.getSeq());
|
||||
return m;
|
||||
}
|
||||
|
||||
private Map<String, Object> listMap(HomesBranch b, Map<Long, String> groupNames) {
|
||||
Map<String, Object> m = new LinkedHashMap<>();
|
||||
m.put("id", b.getId());
|
||||
m.put("name", b.getName());
|
||||
m.put("officeName", b.getOfficeName());
|
||||
m.put("userid", b.getUserid());
|
||||
m.put("tel", b.getTel());
|
||||
m.put("phone", b.getPhone());
|
||||
m.put("email", b.getEmail());
|
||||
m.put("sido", b.getSido());
|
||||
m.put("level", b.getLevel() == null ? 1 : b.getLevel());
|
||||
m.put("grant", b.getGrantFlag() == null ? 0 : b.getGrantFlag());
|
||||
m.put("branchGroupId", b.getBranchGroupId());
|
||||
m.put("branchGroupName", b.getBranchGroupId() == null ? null : groupNames.get(b.getBranchGroupId()));
|
||||
m.put("centerName", b.getCenterName());
|
||||
m.put("hasBusinessLicense", b.isHasBusinessLicense());
|
||||
m.put("isTax", b.getIsTax() == null ? 1 : b.getIsTax());
|
||||
m.put("createdAt", b.getCreatedAt() == null ? null
|
||||
: DT.format(b.getCreatedAt().atZone(KST).toLocalDateTime()));
|
||||
return m;
|
||||
}
|
||||
|
||||
private Map<String, Object> detailMap(HomesBranch b) {
|
||||
Map<String, Object> m = listMap(b, groupNameMap(b.getGroupId()));
|
||||
m.put("fax", b.getFax());
|
||||
m.put("zipcode", b.getZipcode());
|
||||
m.put("address", b.getAddress());
|
||||
m.put("addressDetail", b.getAddressDetail());
|
||||
m.put("isPersonal", !b.isHasBusinessLicense());
|
||||
m.put("accountBank", b.getAccountBank());
|
||||
m.put("accountNumber", b.getAccountNumber());
|
||||
m.put("accountName", b.getAccountName());
|
||||
m.put("contactPhone", b.getContactPhone());
|
||||
m.put("contactNateon", b.getContactNateon());
|
||||
m.put("acceptPhone", b.getAcceptPhone() == null ? 0 : b.getAcceptPhone());
|
||||
m.put("acceptNateon", b.getAcceptNateon() == null ? 0 : b.getAcceptNateon());
|
||||
m.put("memo", b.getMemo());
|
||||
m.put("adminMemo", b.getAdminMemo());
|
||||
m.put("licenseNumber", b.getLicenseNumber());
|
||||
m.put("licenseType", b.getLicenseType());
|
||||
m.put("licenseItem", b.getLicenseItem());
|
||||
m.put("notifyPhones", parseNotify(b.getNotifyPhonesJson()));
|
||||
m.put("permissionOrderDateUpdate", b.isPermissionOrderDateUpdate());
|
||||
m.put("permissionCalculate", b.isPermissionCalculate());
|
||||
m.put("permissionConfig", b.isPermissionConfig());
|
||||
m.put("permissionExcelDownload", b.isPermissionExcelDownload());
|
||||
m.put("permissionChart", b.isPermissionChart());
|
||||
return m;
|
||||
}
|
||||
|
||||
private Map<String, Object> feeEntryMap(HomesBranchFee f, String type) {
|
||||
Map<String, Object> m = new LinkedHashMap<>();
|
||||
m.put("id", f.getId());
|
||||
m.put("type", type);
|
||||
m.put("ispName", f.getCarrier());
|
||||
m.put("carrier", f.getCarrier());
|
||||
m.put("category", "공통");
|
||||
m.put("startDate", f.getStartDate() == null ? null : DT.format(f.getStartDate()));
|
||||
return m;
|
||||
}
|
||||
|
||||
private static List<String> parseNotify(String json) {
|
||||
List<String> phones = new ArrayList<>();
|
||||
if (json != null && json.startsWith("[")) {
|
||||
String inner = json.substring(1, json.endsWith("]") ? json.length() - 1 : json.length()).trim();
|
||||
if (!inner.isEmpty()) {
|
||||
for (String part : inner.split(",")) {
|
||||
phones.add(part.trim().replace("\"", ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
while (phones.size() < 6) phones.add("");
|
||||
return phones.subList(0, 6);
|
||||
}
|
||||
|
||||
private static String toNotifyJson(Object raw) {
|
||||
List<String> phones = new ArrayList<>();
|
||||
if (raw instanceof List<?> list) {
|
||||
for (Object o : list) phones.add(o == null ? "" : String.valueOf(o));
|
||||
}
|
||||
while (phones.size() < 6) phones.add("");
|
||||
StringBuilder sb = new StringBuilder("[");
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (i > 0) sb.append(',');
|
||||
sb.append('"').append(phones.get(i).replace("\"", "")).append('"');
|
||||
}
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String deriveSido(String zipcode, String sido, String address) {
|
||||
if (!blank(sido)) return sido.trim();
|
||||
if (!blank(address)) {
|
||||
String[] parts = address.trim().split("\\s+");
|
||||
if (parts.length > 0) return parts[0];
|
||||
}
|
||||
if (!blank(zipcode) && zipcode.length() >= 2) return zipcode.substring(0, 2);
|
||||
return "";
|
||||
}
|
||||
|
||||
private static boolean blank(String s) { return s == null || s.isBlank(); }
|
||||
private static String str(Object o) { return o == null ? "" : String.valueOf(o).trim(); }
|
||||
private static boolean bool(Object o) {
|
||||
return Boolean.TRUE.equals(o) || "true".equalsIgnoreCase(String.valueOf(o));
|
||||
}
|
||||
private static Long longOrNull(Object o) {
|
||||
if (o == null || "".equals(o) || "null".equals(String.valueOf(o))) return null;
|
||||
if (o instanceof Number n) return n.longValue();
|
||||
try { return Long.parseLong(String.valueOf(o)); } catch (Exception e) { return null; }
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,182 @@
|
||||
package com.bizcare.agent;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 접수별 적용 수수료 현황 — billing_imeere BranchGroupFeeController@order / CenterFeeController@order.
|
||||
*
|
||||
* 적용가능 수수료가 없으면 fail("적용가능한 수수료가 없습니다.").
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/agent/homes/fee")
|
||||
@RequiredArgsConstructor
|
||||
class CareFeeController {
|
||||
private static final ZoneId KST = ZoneId.of("Asia/Seoul");
|
||||
private static final DateTimeFormatter DT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
private final EntityManager em;
|
||||
|
||||
@GetMapping("/order/{receptionId}")
|
||||
@Transactional(readOnly = true)
|
||||
ApiResponse orderFee(@PathVariable Long receptionId,
|
||||
@RequestParam(defaultValue = "branch") String kind,
|
||||
@AuthenticationPrincipal JwtUser u) {
|
||||
HomesReception r = em.find(HomesReception.class, receptionId);
|
||||
if (r == null || !Objects.equals(r.getGroupId(), u.getGroupId())) {
|
||||
return ApiResponse.fail("삭제되었거나 등록되지 않은 접수입니다.");
|
||||
}
|
||||
if ("center".equalsIgnoreCase(kind)) {
|
||||
return centerOrder(r, u);
|
||||
}
|
||||
return branchOrder(r, u);
|
||||
}
|
||||
|
||||
private ApiResponse branchOrder(HomesReception r, JwtUser u) {
|
||||
String branch = blank(r.getBranch()) ? "본지점" : r.getBranch().trim();
|
||||
String carrier = blank(r.getIspName()) ? (r.getCarrier() == null ? "" : r.getCarrier().trim()) : r.getIspName().trim();
|
||||
LocalDateTime orderDate = r.getOrderDate() != null ? r.getOrderDate() : LocalDateTime.now(KST);
|
||||
|
||||
HomesBranchFee alone = findLatestBranchFee(u.getGroupId(), "alone", branch, carrier, orderDate);
|
||||
HomesBranchFee group = findLatestBranchFee(u.getGroupId(), "group",
|
||||
blank(r.getBranchGroup()) ? null : r.getBranchGroup().trim(), carrier, orderDate);
|
||||
// 그룹 수수료는 branchGroupName 매칭; 없으면 동일 통신사 그룹시트 중 최신
|
||||
if (group == null) {
|
||||
group = findLatestBranchFeeByCarrier(u.getGroupId(), "group", carrier, orderDate);
|
||||
}
|
||||
|
||||
if (alone == null && group == null) {
|
||||
return ApiResponse.fail("적용가능한 수수료가 없습니다.");
|
||||
}
|
||||
|
||||
String type = "group";
|
||||
HomesBranchFee selected = group;
|
||||
if (group == null
|
||||
|| (alone != null && !alone.getStartDate().isBefore(group.getStartDate()))) {
|
||||
type = "alone";
|
||||
selected = alone;
|
||||
}
|
||||
return ApiResponse.ok(toBranchView(selected, type, branch, carrier));
|
||||
}
|
||||
|
||||
private ApiResponse centerOrder(HomesReception r, JwtUser u) {
|
||||
String center = blank(r.getProcessor()) ? "본사" : r.getProcessor().trim();
|
||||
String carrier = blank(r.getIspName()) ? (r.getCarrier() == null ? "" : r.getCarrier().trim()) : r.getIspName().trim();
|
||||
LocalDateTime orderDate = r.getOrderDate() != null ? r.getOrderDate() : LocalDateTime.now(KST);
|
||||
|
||||
HomesCenterFee fee = findLatestCenterFee(u.getGroupId(), center, carrier, orderDate);
|
||||
if (fee == null) {
|
||||
return ApiResponse.fail("적용가능한 수수료가 없습니다.");
|
||||
}
|
||||
return ApiResponse.ok(toCenterView(fee, center, carrier));
|
||||
}
|
||||
|
||||
private HomesBranchFee findLatestBranchFee(String groupId, String feeType, String branchOrGroup,
|
||||
String carrier, LocalDateTime orderDate) {
|
||||
if (blank(branchOrGroup) || blank(carrier)) return null;
|
||||
String jpql = "alone".equals(feeType)
|
||||
? "select f from HomesBranchFee f where f.groupId=:g and f.feeType='alone' and f.branchName=:bn and f.carrier=:c and f.startDate<=:d order by f.startDate desc"
|
||||
: "select f from HomesBranchFee f where f.groupId=:g and f.feeType='group' and f.branchGroupName=:bn and f.carrier=:c and f.startDate<=:d order by f.startDate desc";
|
||||
List<HomesBranchFee> list = em.createQuery(jpql, HomesBranchFee.class)
|
||||
.setParameter("g", groupId)
|
||||
.setParameter("bn", branchOrGroup)
|
||||
.setParameter("c", carrier)
|
||||
.setParameter("d", orderDate)
|
||||
.setMaxResults(1)
|
||||
.getResultList();
|
||||
return list.isEmpty() ? null : list.get(0);
|
||||
}
|
||||
|
||||
private HomesBranchFee findLatestBranchFeeByCarrier(String groupId, String feeType, String carrier,
|
||||
LocalDateTime orderDate) {
|
||||
if (blank(carrier)) return null;
|
||||
List<HomesBranchFee> list = em.createQuery(
|
||||
"select f from HomesBranchFee f where f.groupId=:g and f.feeType=:t and f.carrier=:c and f.startDate<=:d order by f.startDate desc",
|
||||
HomesBranchFee.class)
|
||||
.setParameter("g", groupId)
|
||||
.setParameter("t", feeType)
|
||||
.setParameter("c", carrier)
|
||||
.setParameter("d", orderDate)
|
||||
.setMaxResults(1)
|
||||
.getResultList();
|
||||
return list.isEmpty() ? null : list.get(0);
|
||||
}
|
||||
|
||||
private HomesCenterFee findLatestCenterFee(String groupId, String center, String carrier, LocalDateTime orderDate) {
|
||||
if (blank(center) || blank(carrier)) return null;
|
||||
List<HomesCenterFee> list = em.createQuery(
|
||||
"select f from HomesCenterFee f where f.groupId=:g and f.centerName=:cn and f.carrier=:c and f.startDate<=:d order by f.startDate desc",
|
||||
HomesCenterFee.class)
|
||||
.setParameter("g", groupId)
|
||||
.setParameter("cn", center)
|
||||
.setParameter("c", carrier)
|
||||
.setParameter("d", orderDate)
|
||||
.setMaxResults(1)
|
||||
.getResultList();
|
||||
return list.isEmpty() ? null : list.get(0);
|
||||
}
|
||||
|
||||
private Map<String, Object> toBranchView(HomesBranchFee fee, String type, String entityName, String carrier) {
|
||||
Map<String, Object> m = new LinkedHashMap<>();
|
||||
m.put("kind", "branch");
|
||||
m.put("type", type);
|
||||
m.put("feeId", fee.getId());
|
||||
m.put("entityName", entityName);
|
||||
m.put("ispName", carrier);
|
||||
m.put("startDate", fee.getStartDate() == null ? "" : fee.getStartDate().format(DT));
|
||||
m.put("memo", fee.getMemo());
|
||||
m.put("products", productsOfBranch(fee.getId()));
|
||||
return m;
|
||||
}
|
||||
|
||||
private Map<String, Object> toCenterView(HomesCenterFee fee, String entityName, String carrier) {
|
||||
Map<String, Object> m = new LinkedHashMap<>();
|
||||
m.put("kind", "center");
|
||||
m.put("type", "center");
|
||||
m.put("feeId", fee.getId());
|
||||
m.put("entityName", entityName);
|
||||
m.put("ispName", carrier);
|
||||
m.put("startDate", fee.getStartDate() == null ? "" : fee.getStartDate().format(DT));
|
||||
m.put("memo", fee.getMemo());
|
||||
m.put("products", productsOfCenter(fee.getId()));
|
||||
return m;
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> productsOfBranch(Long feeId) {
|
||||
return em.createQuery(
|
||||
"select p from HomesBranchFeeProduct p where p.feeId=:id order by p.id",
|
||||
HomesBranchFeeProduct.class)
|
||||
.setParameter("id", feeId)
|
||||
.getResultList().stream().map(p -> {
|
||||
Map<String, Object> row = new LinkedHashMap<>();
|
||||
row.put("productType", p.getProductType());
|
||||
row.put("productName", p.getProductName());
|
||||
row.put("fee", p.getFee() == null ? 0 : p.getFee());
|
||||
return row;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> productsOfCenter(Long feeId) {
|
||||
return em.createQuery(
|
||||
"select p from HomesCenterFeeProduct p where p.feeId=:id order by p.id",
|
||||
HomesCenterFeeProduct.class)
|
||||
.setParameter("id", feeId)
|
||||
.getResultList().stream().map(p -> {
|
||||
Map<String, Object> row = new LinkedHashMap<>();
|
||||
row.put("productType", p.getProductType());
|
||||
row.put("productName", p.getProductName());
|
||||
row.put("fee", p.getFee() == null ? 0 : p.getFee());
|
||||
return row;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
private static boolean blank(String s) { return s == null || s.isBlank(); }
|
||||
}
|
||||
@@ -2845,6 +2845,7 @@ class CareHomesController {
|
||||
m.put("상품관리", "product");
|
||||
m.put("계약관리", "contract");
|
||||
m.put("접수관리", "reception");
|
||||
m.put("영업점관리", "branch");
|
||||
m.put("정산관리", "invoice");
|
||||
m.put("일정관리", "pending");
|
||||
m.put("예약관리", "booking");
|
||||
@@ -2865,7 +2866,7 @@ class CareHomesController {
|
||||
Map<String, Boolean> exposure = parseMenuFlagsMap(menuFlagsRaw);
|
||||
|
||||
if (isOwner) {
|
||||
for (String id : List.of("home", "product", "contract", "reception", "invoice", "pending", "booking",
|
||||
for (String id : List.of("home", "product", "contract", "reception", "branch", "invoice", "pending", "booking",
|
||||
"customer", "abooks", "report", "setting", "cs", "bbs", "sitemap")) {
|
||||
if (Boolean.FALSE.equals(exposure.get(id))) continue;
|
||||
allowed.add(id);
|
||||
@@ -2923,7 +2924,7 @@ class CareHomesController {
|
||||
|
||||
private Map<String, Boolean> parseMenuFlagsMap(String raw) {
|
||||
Map<String, Boolean> flags = new LinkedHashMap<>();
|
||||
for (String id : List.of("home", "product", "contract", "reception", "invoice", "pending", "booking",
|
||||
for (String id : List.of("home", "product", "contract", "reception", "branch", "invoice", "pending", "booking",
|
||||
"customer", "abooks", "report", "cs", "bbs", "setting", "sitemap")) {
|
||||
flags.put(id, true);
|
||||
}
|
||||
@@ -3069,7 +3070,7 @@ class CareHomesController {
|
||||
private static final Map<String, List<String>> LEVEL_ROWS;
|
||||
static {
|
||||
Map<String, List<String>> rows = new LinkedHashMap<>();
|
||||
rows.put("menu", List.of("상품관리", "계약관리", "접수관리", "정산관리", "일정관리", "예약관리", "고객관리", "장부관리", "통계관리", "환경설정"));
|
||||
rows.put("menu", List.of("상품관리", "계약관리", "접수관리", "영업점관리", "정산관리", "일정관리", "예약관리", "고객관리", "장부관리", "통계관리", "환경설정"));
|
||||
rows.put("product", List.of("목록조회", "상품등록", "상품수정", "상품삭제", "정책관리", "엑셀다운로드"));
|
||||
rows.put("contract", List.of("목록조회", "계약등록", "계약수정", "상태변경", "엑셀다운로드"));
|
||||
rows.put("reception", List.of("목록조회", "접수등록", "접수수정", "진행변경", "엑셀다운로드"));
|
||||
@@ -3120,7 +3121,7 @@ class CareHomesController {
|
||||
for (String menu : menus) {
|
||||
boolean allow = switch (role) {
|
||||
case "총괄", "팀장", "개발자" -> true;
|
||||
case "사원" -> List.of("계약관리", "접수관리", "정산관리", "일정관리", "예약관리", "고객관리", "장부관리").contains(menu);
|
||||
case "사원" -> List.of("계약관리", "접수관리", "영업점관리", "정산관리", "일정관리", "예약관리", "고객관리", "장부관리").contains(menu);
|
||||
case "영업", "딜러" -> List.of("계약관리", "접수관리", "정산관리", "일정관리", "예약관리").contains(menu);
|
||||
default -> false;
|
||||
};
|
||||
|
||||
@@ -29,10 +29,9 @@ class CareReceptionController {
|
||||
private final EntityManager em;
|
||||
private final FileStorageService fileStorage;
|
||||
|
||||
static final List<String> PROGRESS_STATUSES = List.of(
|
||||
"1.접수완료", "2.고객통화", "3.서류검토", "4.개통완료", "5.사은품지급", "6.정산완료", "9.취소");
|
||||
static final List<String> SETTLE_STATUSES = List.of("정산대기", "정산완료", "회수대기", "회수완료");
|
||||
static final List<String> GIFT_STATUSES = List.of("미지급", "지급대기", "지급완료", "반송");
|
||||
static final List<String> PROGRESS_STATUSES = ReceptionStatuses.progressCodes();
|
||||
static final List<String> SETTLE_STATUSES = ReceptionStatuses.centerCodes();
|
||||
static final List<String> GIFT_STATUSES = ReceptionStatuses.giftCodes();
|
||||
static final List<String> CARRIERS = List.of("KT", "SKB", "LGU+", "SKT", "기타");
|
||||
static final List<String> REGIONS = List.of(
|
||||
"서울", "경기", "인천", "강원", "충북", "충남", "대전", "전북", "전남", "광주",
|
||||
@@ -47,7 +46,9 @@ class CareReceptionController {
|
||||
Map<String, Long> counts = new LinkedHashMap<>();
|
||||
counts.put("ALL", (long) filtered.size());
|
||||
for (String st : PROGRESS_STATUSES) {
|
||||
counts.put(st, filtered.stream().filter(r -> st.equals(r.getProgressStatus())).count());
|
||||
counts.put(st, filtered.stream()
|
||||
.filter(r -> st.equals(ReceptionStatuses.normalizeProgress(r.getProgressStatus())))
|
||||
.count());
|
||||
}
|
||||
int fromIdx = Math.max(0, page) * Math.max(1, size);
|
||||
int limit = Math.min(Math.max(size, 1), 200);
|
||||
@@ -60,6 +61,10 @@ class CareReceptionController {
|
||||
data.put("progressStatuses", PROGRESS_STATUSES);
|
||||
data.put("settleStatuses", SETTLE_STATUSES);
|
||||
data.put("giftStatuses", GIFT_STATUSES);
|
||||
data.put("progressStatusLabels", ReceptionStatuses.PROGRESS);
|
||||
data.put("giftStatusLabels", ReceptionStatuses.GIFT);
|
||||
data.put("settleStatusLabels", ReceptionStatuses.CENTER);
|
||||
data.put("giftPlaceLabels", ReceptionStatuses.GIFT_PLACE);
|
||||
data.put("carriers", distinct(filtered, HomesReception::getCarrier, CARRIERS));
|
||||
data.put("branches", distinct(filtered, HomesReception::getBranch, List.of()));
|
||||
data.put("counselors", distinct(filtered, HomesReception::getCounselor, List.of()));
|
||||
@@ -170,32 +175,61 @@ class CareReceptionController {
|
||||
boolean adminOnly = Boolean.TRUE.equals(body.get("adminOnly")) || "true".equalsIgnoreCase(String.valueOf(body.get("adminOnly")));
|
||||
|
||||
boolean statusChanged = false;
|
||||
if (!blank(newStatus) && !Objects.equals(newStatus, r.getProgressStatus())) {
|
||||
r.setProgressStatus(newStatus);
|
||||
statusChanged = true;
|
||||
if ("4.개통완료".equals(newStatus) && blank(r.getGiftStatus())) {
|
||||
r.setGiftStatus("지급대기");
|
||||
}
|
||||
if ("4.개통완료".equals(newStatus) && r.getOpenDate() == null) {
|
||||
r.setOpenDate(LocalDate.now(ZoneId.of("Asia/Seoul")));
|
||||
String prevProgress = ReceptionStatuses.normalizeProgress(r.getProgressStatus());
|
||||
if (!blank(newStatus)) {
|
||||
newStatus = ReceptionStatuses.normalizeProgress(newStatus);
|
||||
if (!Objects.equals(newStatus, prevProgress)) {
|
||||
Set<String> allowed = ReceptionStatuses.orderStatusTransitions(prevProgress);
|
||||
if (("f23".equals(prevProgress) || "f24".equals(prevProgress) || "f25".equals(prevProgress))
|
||||
&& !allowed.isEmpty() && !allowed.contains(newStatus)) {
|
||||
return ApiResponse.fail("정산 관련 상태는 정산현황 메뉴에서 변경하세요. (현재: "
|
||||
+ ReceptionStatuses.progressLabel(prevProgress) + ")");
|
||||
}
|
||||
r.setProgressStatus(newStatus);
|
||||
statusChanged = true;
|
||||
applyOpenSideEffects(r, newStatus, u);
|
||||
}
|
||||
}
|
||||
|
||||
String giftStatus = str(body.get("giftStatus"));
|
||||
boolean giftChanged = false;
|
||||
if (!blank(giftStatus) && !Objects.equals(giftStatus, r.getGiftStatus())) {
|
||||
r.setGiftStatus(giftStatus);
|
||||
giftChanged = true;
|
||||
appendGiftLog(r, giftStatus, str(body.get("giftProgressLog")), u);
|
||||
if ("지급완료".equals(giftStatus) && "4.개통완료".equals(r.getProgressStatus())) {
|
||||
r.setProgressStatus("6.정산완료");
|
||||
r.setSettleStatus("정산완료");
|
||||
statusChanged = true;
|
||||
if (body.containsKey("giftStatus")) {
|
||||
giftStatus = ReceptionStatuses.normalizeGift(giftStatus);
|
||||
String prevGift = ReceptionStatuses.normalizeGift(r.getGiftStatus());
|
||||
if (!Objects.equals(giftStatus, prevGift)) {
|
||||
r.setGiftStatus(blank(giftStatus) ? null : giftStatus);
|
||||
if ("g01".equals(giftStatus) && r.getGiftRequested() == null) {
|
||||
r.setGiftRequested(LocalDate.now(ZoneId.of("Asia/Seoul")));
|
||||
}
|
||||
if ("g07".equals(giftStatus)) {
|
||||
if (r.getGiftSended() == null) {
|
||||
LocalDate today = LocalDate.now(ZoneId.of("Asia/Seoul"));
|
||||
r.setGiftSended(today);
|
||||
r.setGiftDate(today);
|
||||
}
|
||||
String cur = ReceptionStatuses.normalizeProgress(r.getProgressStatus());
|
||||
if ("f14".equals(cur)) {
|
||||
r.setProgressStatus("f23");
|
||||
r.setSettleStatus("h01");
|
||||
statusChanged = true;
|
||||
appendLog(r, "f23", "사은품 지급완료 후 정산대기 자동변경", u, false);
|
||||
}
|
||||
}
|
||||
appendGiftLog(r, blank(giftStatus) ? prevGift : giftStatus, str(body.get("giftProgressLog")), u);
|
||||
} else if (!blank(str(body.get("giftProgressLog")))) {
|
||||
appendGiftLog(r, r.getGiftStatus(), str(body.get("giftProgressLog")), u);
|
||||
}
|
||||
} else if (!blank(str(body.get("giftProgressLog")))) {
|
||||
appendGiftLog(r, r.getGiftStatus(), str(body.get("giftProgressLog")), u);
|
||||
}
|
||||
|
||||
String centerStatus = str(body.containsKey("centerStatus") ? body.get("centerStatus") : body.get("settleStatus"));
|
||||
if (!blank(centerStatus)) {
|
||||
centerStatus = ReceptionStatuses.normalizeCenter(centerStatus);
|
||||
if (!Objects.equals(centerStatus, ReceptionStatuses.normalizeCenter(r.getSettleStatus()))) {
|
||||
r.setSettleStatus(centerStatus);
|
||||
}
|
||||
}
|
||||
|
||||
if (statusChanged || !blank(progressMemo)) {
|
||||
appendLog(r, blank(newStatus) ? r.getProgressStatus() : newStatus, progressMemo, u, adminOnly);
|
||||
}
|
||||
@@ -210,6 +244,30 @@ class CareReceptionController {
|
||||
return ApiResponse.ok(toProgressDetail(r, u));
|
||||
}
|
||||
|
||||
/** f14 개통완료 시 사은품 g01 + 입력처 h01 + 개통일 */
|
||||
private void applyOpenSideEffects(HomesReception r, String newStatus, JwtUser u) {
|
||||
if ("f22".equals(newStatus) && r.getCancelDate() == null) {
|
||||
r.setCancelDate(LocalDate.now(ZoneId.of("Asia/Seoul")));
|
||||
}
|
||||
if (ReceptionStatuses.isPreCalc(newStatus)) {
|
||||
r.setReceptionCostId(null);
|
||||
}
|
||||
if (!"f14".equals(newStatus)) return;
|
||||
if (r.getOpenDate() == null) {
|
||||
r.setOpenDate(LocalDate.now(ZoneId.of("Asia/Seoul")));
|
||||
}
|
||||
String gift = ReceptionStatuses.normalizeGift(r.getGiftStatus());
|
||||
if (blank(gift)) {
|
||||
r.setGiftStatus("g01");
|
||||
if (r.getGiftRequested() == null) {
|
||||
r.setGiftRequested(LocalDate.now(ZoneId.of("Asia/Seoul")));
|
||||
}
|
||||
appendGiftLog(r, "g01", "개통완료 후 자동변경", u);
|
||||
}
|
||||
String center = ReceptionStatuses.normalizeCenter(r.getSettleStatus());
|
||||
r.setSettleStatus(blank(center) ? "h01" : center);
|
||||
}
|
||||
|
||||
@DeleteMapping("/receptions/progress-log/{logId}")
|
||||
@Transactional
|
||||
ApiResponse deleteProgressLog(@PathVariable Long logId, @AuthenticationPrincipal JwtUser u) {
|
||||
@@ -235,9 +293,12 @@ class CareReceptionController {
|
||||
r.setGroupId(u.getGroupId());
|
||||
apply(r, body);
|
||||
if (r.getOrderDate() == null) r.setOrderDate(LocalDateTime.now(ZoneId.of("Asia/Seoul")));
|
||||
if (blank(r.getProgressStatus())) r.setProgressStatus("1.접수완료");
|
||||
if (blank(r.getSettleStatus())) r.setSettleStatus("정산대기");
|
||||
if (blank(r.getGiftStatus())) r.setGiftStatus("미지급");
|
||||
if (blank(r.getProgressStatus())) r.setProgressStatus("f01");
|
||||
else r.setProgressStatus(ReceptionStatuses.normalizeProgress(r.getProgressStatus()));
|
||||
if (blank(r.getSettleStatus())) r.setSettleStatus("h01");
|
||||
else r.setSettleStatus(ReceptionStatuses.normalizeCenter(r.getSettleStatus()));
|
||||
if (blank(r.getGiftStatus()) || "미지급".equals(r.getGiftStatus())) r.setGiftStatus(null);
|
||||
else r.setGiftStatus(ReceptionStatuses.normalizeGift(r.getGiftStatus()));
|
||||
if (blank(r.getOrderNumber())) r.setOrderNumber(genOrderNumber());
|
||||
em.persist(r);
|
||||
em.flush();
|
||||
@@ -313,12 +374,13 @@ class CareReceptionController {
|
||||
|
||||
int n = 0;
|
||||
for (HomesReception r : rows) {
|
||||
r.setProgressStatus(status);
|
||||
String normalized = ReceptionStatuses.normalizeProgress(status);
|
||||
r.setProgressStatus(normalized);
|
||||
if (!blank(processor)) r.setProcessor(processor);
|
||||
if (opened != null) r.setOpenDate(opened);
|
||||
if (canceled != null) r.setCancelDate(canceled);
|
||||
if ("4.개통완료".equals(status) && blank(r.getGiftStatus())) r.setGiftStatus("지급대기");
|
||||
appendLog(r, status, memo, u, adminOnly);
|
||||
applyOpenSideEffects(r, normalized, u);
|
||||
appendLog(r, normalized, memo, u, adminOnly);
|
||||
n++;
|
||||
}
|
||||
writeLog(u, "RECEPTION", "접수-일괄진행", "접수 " + n + "건 진행상황을 [" + status + "]로 변경하였습니다.");
|
||||
@@ -359,7 +421,8 @@ class CareReceptionController {
|
||||
|
||||
int n = 0;
|
||||
for (HomesReception r : rows) {
|
||||
r.setGiftStatus(status);
|
||||
String normalized = ReceptionStatuses.normalizeGift(status);
|
||||
r.setGiftStatus(blank(normalized) ? null : normalized);
|
||||
if (!blank(place)) r.setGiftPlace(place);
|
||||
if (!blank(deliveryCompany)) r.setDeliveryCompany(deliveryCompany);
|
||||
if (!blank(trackingNumber)) r.setTrackingNumber(trackingNumber);
|
||||
@@ -368,7 +431,22 @@ class CareReceptionController {
|
||||
r.setGiftSended(sended);
|
||||
r.setGiftDate(sended);
|
||||
}
|
||||
appendGiftLog(r, status, giftMemo, u);
|
||||
if ("g01".equals(normalized) && r.getGiftRequested() == null) {
|
||||
r.setGiftRequested(LocalDate.now(ZoneId.of("Asia/Seoul")));
|
||||
}
|
||||
if ("g07".equals(normalized)) {
|
||||
if (r.getGiftSended() == null) {
|
||||
LocalDate today = LocalDate.now(ZoneId.of("Asia/Seoul"));
|
||||
r.setGiftSended(today);
|
||||
r.setGiftDate(today);
|
||||
}
|
||||
if ("f14".equals(ReceptionStatuses.normalizeProgress(r.getProgressStatus()))) {
|
||||
r.setProgressStatus("f23");
|
||||
r.setSettleStatus("h01");
|
||||
appendLog(r, "f23", "사은품 일괄지급완료 후 정산대기", u, false);
|
||||
}
|
||||
}
|
||||
appendGiftLog(r, blank(normalized) ? status : normalized, giftMemo, u);
|
||||
n++;
|
||||
}
|
||||
writeLog(u, "RECEPTION", "사은품-일괄", "접수 " + n + "건 사은품진행을 [" + status + "]로 변경하였습니다.");
|
||||
@@ -385,9 +463,9 @@ class CareReceptionController {
|
||||
for (Long id : ids) {
|
||||
HomesReception r = findOwned(id, u);
|
||||
if (r == null) return ApiResponse.fail("접수 리스트가 올바르지 않습니다.");
|
||||
// 입력처 정산이 비어있거나 미지정인 건만 대상
|
||||
if (!blank(r.getSettleStatus()) && !"정산대기".equals(r.getSettleStatus())
|
||||
&& !"미지정".equals(r.getSettleStatus())) {
|
||||
// 입력처 정산이 비어있거나 정산대기(h01)인 건만 대상
|
||||
String st = ReceptionStatuses.normalizeCenter(r.getSettleStatus());
|
||||
if (!blank(st) && !"h01".equals(st)) {
|
||||
return ApiResponse.fail("접수 리스트가 올바르지 않습니다.");
|
||||
}
|
||||
rows.add(r);
|
||||
@@ -395,7 +473,7 @@ class CareReceptionController {
|
||||
|
||||
int n = 0;
|
||||
for (HomesReception r : rows) {
|
||||
r.setSettleStatus("정산대기");
|
||||
r.setSettleStatus("h01");
|
||||
appendLog(r, r.getProgressStatus(), "[일괄변경] 입력처 정산대기", u, false);
|
||||
n++;
|
||||
}
|
||||
@@ -540,8 +618,10 @@ class CareReceptionController {
|
||||
r.setGiftCategory(giftCategory);
|
||||
r.setGiftPlace(giftPlaceCode);
|
||||
r.setGiftDate(parseDate(str(gift.get("giftDate"))));
|
||||
r.setGiftStatus(blank(giftType) || "a01".equals(giftType) ? "미지급" : "지급대기");
|
||||
r.setGiftCashAmount(toDecimal(gift.get("cashAmount")));
|
||||
r.setGiftStatus(blank(giftType) || "a01".equals(giftType) ? null : "g01");
|
||||
if ("g01".equals(r.getGiftStatus())) {
|
||||
r.setGiftRequested(LocalDate.now(ZoneId.of("Asia/Seoul")));
|
||||
} r.setGiftCashAmount(toDecimal(gift.get("cashAmount")));
|
||||
r.setGiftGoods(str(gift.get("goods")));
|
||||
r.setGiftGoodsPrice(toDecimal(gift.get("goodsPrice")));
|
||||
r.setGiftBank(str(gift.get("accountBank")));
|
||||
@@ -559,8 +639,8 @@ class CareReceptionController {
|
||||
r.setPaymentCardYear(str(payment.get("cardYear")));
|
||||
r.setPaymentCardMonth(str(payment.get("cardMonth")));
|
||||
r.setPaymentCardNumber(str(payment.get("cardNumber")));
|
||||
r.setProgressStatus("1.접수완료");
|
||||
r.setSettleStatus("정산대기");
|
||||
r.setProgressStatus("f01");
|
||||
r.setSettleStatus("h01");
|
||||
r.setOrderNumber(genOrderNumber());
|
||||
r.setProcessor(r.getCounselor());
|
||||
r.setDetailProgress("신규신청");
|
||||
@@ -766,9 +846,21 @@ class CareReceptionController {
|
||||
LocalDate gd = r.getGiftSended() != null ? r.getGiftSended() : r.getGiftDate();
|
||||
if (gd == null || !gd.equals(giftSended)) return false;
|
||||
}
|
||||
if (progressF != null && !progressF.equals(r.getProgressStatus())) return false;
|
||||
if (settle != null && !settle.equals(r.getSettleStatus())) return false;
|
||||
if (giftStatus != null && !giftStatus.equals(r.getGiftStatus())) return false;
|
||||
if (progressF != null) {
|
||||
String rp = ReceptionStatuses.normalizeProgress(r.getProgressStatus());
|
||||
String fp = ReceptionStatuses.normalizeProgress(progressF);
|
||||
if (!fp.equals(rp) && !progressF.equals(r.getProgressStatus())) return false;
|
||||
}
|
||||
if (settle != null) {
|
||||
String rs = ReceptionStatuses.normalizeCenter(r.getSettleStatus());
|
||||
String fs = ReceptionStatuses.normalizeCenter(settle);
|
||||
if (!fs.equals(rs) && !settle.equals(r.getSettleStatus())) return false;
|
||||
}
|
||||
if (giftStatus != null) {
|
||||
String rg = ReceptionStatuses.normalizeGift(r.getGiftStatus());
|
||||
String fg = ReceptionStatuses.normalizeGift(giftStatus);
|
||||
if (!fg.equals(rg) && !giftStatus.equals(r.getGiftStatus())) return false;
|
||||
}
|
||||
if (carrier != null && !carrier.equals(r.getCarrier()) && !carrier.equals(r.getIspName())) return false;
|
||||
if (ispName != null) {
|
||||
String hay = (nullToEmpty(r.getIspName()) + " " + nullToEmpty(r.getCarrier())).toLowerCase();
|
||||
@@ -829,7 +921,7 @@ class CareReceptionController {
|
||||
if (d.containsKey("customerName")) r.setCustomerName(str(d.get("customerName")));
|
||||
if (d.containsKey("phone")) r.setPhone(str(d.get("phone")));
|
||||
if (d.containsKey("region")) r.setRegion(str(d.get("region")));
|
||||
if (d.containsKey("progressStatus")) r.setProgressStatus(str(d.get("progressStatus")));
|
||||
if (d.containsKey("progressStatus")) r.setProgressStatus(ReceptionStatuses.normalizeProgress(str(d.get("progressStatus"))));
|
||||
if (d.containsKey("orderNumber")) r.setOrderNumber(str(d.get("orderNumber")));
|
||||
if (d.containsKey("ispId")) r.setIspId(toLong(d.get("ispId")));
|
||||
if (d.containsKey("ispName")) r.setIspName(str(d.get("ispName")));
|
||||
@@ -838,11 +930,13 @@ class CareReceptionController {
|
||||
if (d.containsKey("detailProgress")) r.setDetailProgress(str(d.get("detailProgress")));
|
||||
if (d.containsKey("paymentType")) r.setPaymentType(str(d.get("paymentType")));
|
||||
if (d.containsKey("amount")) r.setAmount(toDecimal(d.get("amount")));
|
||||
if (d.containsKey("settleStatus")) r.setSettleStatus(str(d.get("settleStatus")));
|
||||
if (d.containsKey("settleStatus")) r.setSettleStatus(ReceptionStatuses.normalizeCenter(str(d.get("settleStatus"))));
|
||||
if (d.containsKey("openDate")) r.setOpenDate(parseDate(str(d.get("openDate"))));
|
||||
if (d.containsKey("giftDate")) r.setGiftDate(parseDate(str(d.get("giftDate"))));
|
||||
if (d.containsKey("giftStatus")) r.setGiftStatus(str(d.get("giftStatus")));
|
||||
if (d.containsKey("giftPlace")) r.setGiftPlace(str(d.get("giftPlace")));
|
||||
if (d.containsKey("giftStatus")) {
|
||||
String g = ReceptionStatuses.normalizeGift(str(d.get("giftStatus")));
|
||||
r.setGiftStatus(blank(g) ? null : g);
|
||||
} if (d.containsKey("giftPlace")) r.setGiftPlace(str(d.get("giftPlace")));
|
||||
if (d.containsKey("agreementName")) r.setAgreementName(str(d.get("agreementName")));
|
||||
if (d.containsKey("contractNumber")) r.setContractNumber(str(d.get("contractNumber")));
|
||||
if (d.containsKey("identifyNumber")) r.setIdentifyNumber(str(d.get("identifyNumber")));
|
||||
@@ -953,12 +1047,14 @@ class CareReceptionController {
|
||||
data.put("progressStatuses", PROGRESS_STATUSES);
|
||||
data.put("giftStatuses", GIFT_STATUSES);
|
||||
data.put("settleStatuses", SETTLE_STATUSES);
|
||||
Map<String, String> statusOptions = new LinkedHashMap<>();
|
||||
for (String s : PROGRESS_STATUSES) statusOptions.put(s, s);
|
||||
data.put("statusOptions", statusOptions);
|
||||
Map<String, String> giftStatusOptions = new LinkedHashMap<>();
|
||||
for (String s : GIFT_STATUSES) giftStatusOptions.put(s, s);
|
||||
data.put("giftStatusOptions", giftStatusOptions);
|
||||
data.put("progressStatusLabels", ReceptionStatuses.PROGRESS);
|
||||
data.put("giftStatusLabels", ReceptionStatuses.GIFT);
|
||||
data.put("settleStatusLabels", ReceptionStatuses.CENTER);
|
||||
data.put("statusOptions", new LinkedHashMap<>(ReceptionStatuses.PROGRESS));
|
||||
data.put("giftStatusOptions", new LinkedHashMap<>(ReceptionStatuses.GIFT));
|
||||
data.put("centerStatusOptions", new LinkedHashMap<>(ReceptionStatuses.CENTER));
|
||||
data.put("allowedProgressStatuses", new ArrayList<>(
|
||||
ReceptionStatuses.orderStatusTransitions(ReceptionStatuses.normalizeProgress(r.getProgressStatus()))));
|
||||
// flat alias for list edit form compatibility
|
||||
data.putAll(reception);
|
||||
return data;
|
||||
@@ -1003,6 +1099,8 @@ class CareReceptionController {
|
||||
m.put("addressDetail", r.getAddressDetail());
|
||||
m.put("region", r.getRegion());
|
||||
m.put("progressStatus", r.getProgressStatus());
|
||||
m.put("progressStatusLabel", ReceptionStatuses.progressLabel(ReceptionStatuses.normalizeProgress(r.getProgressStatus())));
|
||||
m.put("status", ReceptionStatuses.progressLabel(ReceptionStatuses.normalizeProgress(r.getProgressStatus())));
|
||||
m.put("orderNumber", r.getOrderNumber());
|
||||
m.put("ispId", r.getIspId());
|
||||
m.put("ispName", r.getIspName());
|
||||
@@ -1038,8 +1136,11 @@ class CareReceptionController {
|
||||
m.put("sido", r.getRegion());
|
||||
m.put("opened", r.getOpenDate() == null ? null : r.getOpenDate().toString());
|
||||
m.put("canceled", r.getCancelDate() == null ? null : r.getCancelDate().toString());
|
||||
m.put("status", r.getProgressStatus());
|
||||
m.put("giftType", r.getGiftCategory());
|
||||
m.put("giftStatusLabel", ReceptionStatuses.giftLabel(ReceptionStatuses.normalizeGift(r.getGiftStatus())));
|
||||
m.put("settleStatusLabel", ReceptionStatuses.centerLabel(ReceptionStatuses.normalizeCenter(r.getSettleStatus())));
|
||||
m.put("centerStatus", r.getSettleStatus());
|
||||
m.put("centerStatusLabel", ReceptionStatuses.centerLabel(ReceptionStatuses.normalizeCenter(r.getSettleStatus())));
|
||||
m.put("giftSended", r.getGiftSended() == null
|
||||
? (r.getGiftDate() == null ? null : r.getGiftDate().toString())
|
||||
: r.getGiftSended().toString());
|
||||
@@ -1050,7 +1151,8 @@ class CareReceptionController {
|
||||
if (r.getGiftCashAmount() != null) giftAmt = giftAmt.add(r.getGiftCashAmount());
|
||||
if (r.getGiftGoodsPrice() != null) giftAmt = giftAmt.add(r.getGiftGoodsPrice());
|
||||
if (giftAmt.signum() == 0 && r.getAmount() != null
|
||||
&& r.getGiftStatus() != null && !"미지급".equals(r.getGiftStatus()) && !"없음".equals(r.getGiftCategory())) {
|
||||
&& r.getGiftStatus() != null && !r.getGiftStatus().isBlank()
|
||||
&& !"미지급".equals(r.getGiftStatus()) && !"없음".equals(r.getGiftCategory())) {
|
||||
giftAmt = r.getAmount();
|
||||
}
|
||||
m.put("giftAmount", giftAmt.signum() == 0 ? null : giftAmt);
|
||||
|
||||
@@ -71,8 +71,28 @@ class DataInitializer implements CommandLineRunner {
|
||||
seedScheduleSampleIfEmpty();
|
||||
seedPostitsIfEmpty();
|
||||
seedStockInfoSampleIfEmpty();
|
||||
migrateReceptionStatusesToCodes();
|
||||
seedCalculateSamplesIfEmpty();
|
||||
seedFeeSheetsIfEmpty();
|
||||
seedBranchesIfEmpty();
|
||||
}
|
||||
|
||||
/** 구 한글 진행/사은품/입력처 상태를 billing 코드(f/g/h)로 변환 */
|
||||
private void migrateReceptionStatusesToCodes() {
|
||||
List<HomesReception> rows = em.createQuery("select r from HomesReception r", HomesReception.class).getResultList();
|
||||
for (HomesReception r : rows) {
|
||||
String p = ReceptionStatuses.normalizeProgress(r.getProgressStatus());
|
||||
if (p != null && !p.equals(r.getProgressStatus())) r.setProgressStatus(p.isBlank() ? null : p);
|
||||
String g = ReceptionStatuses.normalizeGift(r.getGiftStatus());
|
||||
if (g != null && !g.equals(nullToEmpty(r.getGiftStatus()))) r.setGiftStatus(g.isBlank() ? null : g);
|
||||
String c = ReceptionStatuses.normalizeCenter(r.getSettleStatus());
|
||||
if (c != null && !c.equals(nullToEmpty(r.getSettleStatus()))) r.setSettleStatus(c.isBlank() ? null : c);
|
||||
}
|
||||
em.flush();
|
||||
}
|
||||
|
||||
private static String nullToEmpty(String s) { return s == null ? "" : s; }
|
||||
|
||||
private void seedStockInfoSampleIfEmpty() {
|
||||
Long exists = em.createQuery("select count(s) from Stock s where s.groupId='demo' and s.serial='0018987'", Long.class).getSingleResult();
|
||||
if (exists != null && exists > 0) return;
|
||||
@@ -2325,16 +2345,16 @@ class DataInitializer implements CommandLineRunner {
|
||||
em.flush();
|
||||
if (em.createQuery("select count(r) from HomesReception r where r.groupId='demo'", Long.class).getSingleResult() == 0) {
|
||||
Object[][] rows = {
|
||||
{LocalDateTime.of(2026, 7, 10, 9, 12), "김상담", "강남점", "KT", "상품권", "인터넷", "기가인터넷 1G", "홍*동", "010-1111-2222", "서울", "1.접수완료", "SAMPLE-00001", "서울입고", "박처리", "접수", "현금", "100000", "정산대기", null, null, "미지급", "본사", "36개월", "02-1234-5678"},
|
||||
{LocalDateTime.of(2026, 7, 10, 10, 30), "이상담", "서초점", "SKB", "가전", "TV", "B tv 프리미엄", "김*수", "010-2222-3333", "경기", "2.고객통화", "SAMPLE-00002", "", "최처리", "통화완료", "계좌", "80000", "정산대기", null, null, "지급대기", "영업점", "24개월", ""},
|
||||
{LocalDateTime.of(2026, 7, 9, 14, 5), "김상담", "강남점", "LGU+", "상품권", "인터넷", "U+ 인터넷", "박*지", "010-3333-4444", "인천", "4.개통완료", "SAMPLE-00003", "서울입고", "박처리", "개통", "현금", "120000", "정산대기", LocalDate.of(2026, 7, 9), null, "미지급", "본사", "36개월", "032-555-1212"},
|
||||
{LocalDateTime.of(2026, 7, 8, 11, 20), "정상담", "송파점", "KT", "캐시백", "정수기", "청호 450", "최*아", "010-4444-5555", "서울", "4.개통완료", "SAMPLE-00004", "물류완료", "이처리", "설치완료", "카드", "150000", "정산완료", LocalDate.of(2026, 7, 8), LocalDate.of(2026, 7, 10), "지급완료", "본사", "60개월", ""},
|
||||
{LocalDateTime.of(2026, 7, 8, 16, 40), "이상담", "서초점", "SKT", "상품권", "전화", "집전화 스마트", "정*민", "010-5555-6666", "부산", "3.서류검토", "SAMPLE-00005", "", "최처리", "서류요청", "현금", "15000", "정산대기", null, null, "미지급", "본사", "24개월", ""},
|
||||
{LocalDateTime.of(2026, 7, 7, 9, 50), "김상담", "강남점", "KT", "가전", "공기청정기", "퓨리케어 360", "이*수", "010-6666-7777", "서울", "5.사은품지급", "SAMPLE-00006", "서울입고", "박처리", "사은품발송", "계좌", "90000", "정산대기", LocalDate.of(2026, 7, 6), LocalDate.of(2026, 7, 7), "지급완료", "본사", "36개월", ""},
|
||||
{LocalDateTime.of(2026, 7, 6, 13, 15), "정상담", "송파점", "SKB", "상품권", "인터넷", "B tv 인터넷", "윤*희", "010-7777-8888", "경기", "6.정산완료", "SAMPLE-00007", "완료", "이처리", "정산", "현금", "75000", "정산완료", LocalDate.of(2026, 7, 5), LocalDate.of(2026, 7, 6), "지급완료", "영업점", "36개월", ""},
|
||||
{LocalDateTime.of(2026, 7, 5, 15, 0), "이상담", "서초점", "LGU+", "캐시백", "와이파이", "와이파이 메시", "한*진", "010-8888-9999", "대전", "9.취소", "SAMPLE-00008", "", "최처리", "고객취소", "", "0", "회수대기", null, null, "반송", "", "12개월", ""},
|
||||
{LocalDateTime.of(2026, 7, 11, 8, 45), "김상담", "강남점", "KT", "상품권", "인터넷", "안심 인터넷 베이직", "오*라", "010-1212-3434", "서울", "1.접수완료", "SAMPLE-00009", "", "박처리", "접수", "현금", "60000", "정산대기", null, null, "미지급", "본사", "36개월", ""},
|
||||
{LocalDateTime.of(2026, 7, 11, 11, 10), "정상담", "송파점", "SKB", "가전", "비데", "스스로케어 비데", "서*호", "010-5656-7878", "경남", "2.고객통화", "SAMPLE-00010", "물류대기", "이처리", "통화예약", "계좌", "60000", "정산대기", null, null, "지급대기", "본사", "36개월", ""},
|
||||
{LocalDateTime.of(2026, 7, 10, 9, 12), "김상담", "강남점", "KT", "상품권", "인터넷", "기가인터넷 1G", "홍*동", "010-1111-2222", "서울", "f01", "SAMPLE-00001", "서울입고", "박처리", "접수", "현금", "100000", "h01", null, null, "", "b01", "36개월", "02-1234-5678"},
|
||||
{LocalDateTime.of(2026, 7, 10, 10, 30), "이상담", "서초점", "SKB", "가전", "TV", "B tv 프리미엄", "김*수", "010-2222-3333", "경기", "f03", "SAMPLE-00002", "", "최처리", "통화완료", "계좌", "80000", "h01", null, null, "g01", "b02", "24개월", ""},
|
||||
{LocalDateTime.of(2026, 7, 9, 14, 5), "김상담", "강남점", "LGU+", "상품권", "인터넷", "U+ 인터넷", "박*지", "010-3333-4444", "인천", "f14", "SAMPLE-00003", "서울입고", "박처리", "개통", "현금", "120000", "h01", LocalDate.of(2026, 7, 9), null, "g01", "b01", "36개월", "032-555-1212"},
|
||||
{LocalDateTime.of(2026, 7, 8, 11, 20), "정상담", "송파점", "KT", "캐시백", "정수기", "청호 450", "최*아", "010-4444-5555", "서울", "f23", "SAMPLE-00004", "물류완료", "이처리", "설치완료", "카드", "150000", "h01", LocalDate.of(2026, 7, 8), LocalDate.of(2026, 7, 10), "g07", "b01", "60개월", ""},
|
||||
{LocalDateTime.of(2026, 7, 8, 16, 40), "이상담", "서초점", "SKT", "상품권", "전화", "집전화 스마트", "정*민", "010-5555-6666", "부산", "f05", "SAMPLE-00005", "", "최처리", "서류요청", "현금", "15000", "h01", null, null, "", "b01", "24개월", ""},
|
||||
{LocalDateTime.of(2026, 7, 7, 9, 50), "김상담", "강남점", "KT", "가전", "공기청정기", "퓨리케어 360", "이*수", "010-6666-7777", "서울", "f14", "SAMPLE-00006", "서울입고", "박처리", "사은품발송", "계좌", "90000", "h01", LocalDate.of(2026, 7, 6), LocalDate.of(2026, 7, 7), "g07", "b01", "36개월", ""},
|
||||
{LocalDateTime.of(2026, 7, 6, 13, 15), "정상담", "송파점", "SKB", "상품권", "인터넷", "B tv 인터넷", "윤*희", "010-7777-8888", "경기", "f24", "SAMPLE-00007", "완료", "이처리", "정산", "현금", "75000", "h02", LocalDate.of(2026, 7, 5), LocalDate.of(2026, 7, 6), "g07", "b02", "36개월", ""},
|
||||
{LocalDateTime.of(2026, 7, 5, 15, 0), "이상담", "서초점", "LGU+", "캐시백", "와이파이", "와이파이 메시", "한*진", "010-8888-9999", "대전", "f11", "SAMPLE-00008", "", "최처리", "고객취소", "", "0", "h05", null, null, "g03", "", "12개월", ""},
|
||||
{LocalDateTime.of(2026, 7, 11, 8, 45), "김상담", "강남점", "KT", "상품권", "인터넷", "안심 인터넷 베이직", "오*라", "010-1212-3434", "서울", "f01", "SAMPLE-00009", "", "박처리", "접수", "현금", "60000", "h01", null, null, "", "b01", "36개월", ""},
|
||||
{LocalDateTime.of(2026, 7, 11, 11, 10), "정상담", "송파점", "SKB", "가전", "비데", "스스로케어 비데", "서*호", "010-5656-7878", "경남", "f03", "SAMPLE-00010", "물류대기", "이처리", "통화예약", "계좌", "60000", "h01", null, null, "g01", "b01", "36개월", ""},
|
||||
};
|
||||
for (Object[] s : rows) {
|
||||
HomesReception r = new HomesReception();
|
||||
@@ -2359,7 +2379,7 @@ class DataInitializer implements CommandLineRunner {
|
||||
r.setSettleStatus(String.valueOf(s[17]));
|
||||
r.setOpenDate(s[18] == null ? null : (LocalDate) s[18]);
|
||||
r.setGiftDate(s[19] == null ? null : (LocalDate) s[19]);
|
||||
r.setGiftStatus(String.valueOf(s[20]));
|
||||
r.setGiftStatus(String.valueOf(s[20]).isBlank() ? null : String.valueOf(s[20]));
|
||||
r.setGiftPlace(String.valueOf(s[21]));
|
||||
r.setAgreementName(String.valueOf(s[22]));
|
||||
r.setContractNumber(String.valueOf(s[23]));
|
||||
@@ -2841,7 +2861,8 @@ class DataInitializer implements CommandLineRunner {
|
||||
if (r.getTel() == null || r.getTel().isBlank()) r.setTel("02-100" + i);
|
||||
if (r.getGiftSended() == null && r.getGiftDate() != null) r.setGiftSended(r.getGiftDate());
|
||||
if (r.getGiftCashAmount() == null && r.getAmount() != null
|
||||
&& r.getGiftStatus() != null && !"미지급".equals(r.getGiftStatus()) && !"없음".equals(r.getGiftCategory())) {
|
||||
&& r.getGiftStatus() != null && !r.getGiftStatus().isBlank()
|
||||
&& !"미지급".equals(r.getGiftStatus()) && !"없음".equals(r.getGiftCategory())) {
|
||||
r.setGiftCashAmount(r.getAmount());
|
||||
}
|
||||
if (r.getIspName() == null || r.getIspName().isBlank()) r.setIspName(r.getCarrier());
|
||||
@@ -2962,4 +2983,485 @@ class DataInitializer implements CommandLineRunner {
|
||||
em.persist(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* billing_react 정산현황 테스트용 샘플.
|
||||
* 영업점/입력처 각각 가정산·정산대기·정산완료·송금(입금)완료 단계를 채운다.
|
||||
*/
|
||||
private void seedCalculateSamplesIfEmpty() {
|
||||
Long exists = em.createQuery(
|
||||
"select count(r) from HomesReception r where r.groupId='demo' and r.orderNumber like 'CALC-%'",
|
||||
Long.class)
|
||||
.getSingleResult();
|
||||
if (exists != null && exists > 0) return;
|
||||
|
||||
LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Seoul"));
|
||||
String[][] branches = {
|
||||
{"강남점", "본사그룹", "서울", "김상담", "박처리", "1599-1001"},
|
||||
{"서초점", "본사그룹", "경기", "이상담", "최처리", "1599-1002"},
|
||||
{"송파점", "동부그룹", "서울", "정상담", "이처리", "1599-1003"},
|
||||
};
|
||||
String[] carriers = {"KT", "SKB", "LGU+"};
|
||||
String[] products = {"기가인터넷 1G", "B tv 프리미엄", "U+ 인터넷", "안심 인터넷"};
|
||||
int seq = 1;
|
||||
|
||||
// ---- 영업점: 가정산 (cost 없음, f23 / 환수 f19·f22) ----
|
||||
for (String[] b : branches) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
HomesReception r = calcReception(
|
||||
"CALC-" + String.format("%04d", seq++),
|
||||
now.minusDays(3 + i), b, carriers[i % 3], products[i % 4],
|
||||
"정산고객" + seq, "f23", "h01", 100000 + i * 10000, true);
|
||||
em.persist(r);
|
||||
}
|
||||
HomesReception claw = calcReception(
|
||||
"CALC-" + String.format("%04d", seq++),
|
||||
now.minusDays(20), b, carriers[0], products[0],
|
||||
"환수고객" + seq, "f19", "h05", 80000, true);
|
||||
claw.setPrevProgressStatus("f14");
|
||||
em.persist(claw);
|
||||
}
|
||||
|
||||
// ---- 영업점: 정산대기 (cost 있음, group 없음) ----
|
||||
for (String[] b : branches) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
HomesReception r = calcReception(
|
||||
"CALC-" + String.format("%04d", seq++),
|
||||
now.minusDays(10 + i), b, carriers[i % 3], products[i % 4],
|
||||
"대기고객" + seq, "f23", "h01", 120000 + i * 5000, true);
|
||||
em.persist(r);
|
||||
em.flush();
|
||||
HomesReceptionCost c = calcCost(r, "i01", 1);
|
||||
em.persist(c);
|
||||
em.flush();
|
||||
r.setReceptionCostId(c.getId());
|
||||
}
|
||||
HomesReception claw = calcReception(
|
||||
"CALC-" + String.format("%04d", seq++),
|
||||
now.minusDays(25), b, carriers[1], products[1],
|
||||
"대기환수" + seq, "f22", "h08", 70000, true);
|
||||
claw.setPrevProgressStatus("f14");
|
||||
em.persist(claw);
|
||||
em.flush();
|
||||
HomesReceptionCost cc = calcCost(claw, "i05", -1);
|
||||
em.persist(cc);
|
||||
em.flush();
|
||||
claw.setReceptionCostId(cc.getId());
|
||||
}
|
||||
|
||||
// ---- 영업점: 정산완료 그룹 (미송금) ----
|
||||
for (String[] b : branches) {
|
||||
HomesReceptionCostGroup g = new HomesReceptionCostGroup();
|
||||
g.setGroupId("demo");
|
||||
g.setBranchName(b[0]);
|
||||
g.setPlusAmt(5000);
|
||||
g.setMinusAmt(0);
|
||||
g.setIsTax(1);
|
||||
g.setRate(BigDecimal.valueOf(10));
|
||||
g.setCompletedAt(now.minusDays(2));
|
||||
g.setMemo("샘플 정산완료 — " + b[0]);
|
||||
g.setBank("국민");
|
||||
g.setAccountNumber("123-456-" + b[0].hashCode() % 10000);
|
||||
g.setAccountName(b[0] + "대표");
|
||||
em.persist(g);
|
||||
em.flush();
|
||||
|
||||
int lineSum = 0;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
HomesReception r = calcReception(
|
||||
"CALC-" + String.format("%04d", seq++),
|
||||
now.minusDays(15 + i), b, carriers[i % 3], products[i % 4],
|
||||
"완료고객" + seq, "f24", "h02", 110000 + i * 8000, true);
|
||||
em.persist(r);
|
||||
em.flush();
|
||||
HomesReceptionCost c = calcCost(r, "i01", 1);
|
||||
c.setCostGroupId(g.getId());
|
||||
em.persist(c);
|
||||
em.flush();
|
||||
r.setReceptionCostId(c.getId());
|
||||
lineSum += c.getTotal();
|
||||
}
|
||||
// 환수 1건
|
||||
HomesReception claw = calcReception(
|
||||
"CALC-" + String.format("%04d", seq++),
|
||||
now.minusDays(30), b, carriers[2], products[2],
|
||||
"완료환수" + seq, "f26", "h09", 50000, true);
|
||||
em.persist(claw);
|
||||
em.flush();
|
||||
HomesReceptionCost cc = calcCost(claw, "i02", -1);
|
||||
cc.setCostGroupId(g.getId());
|
||||
em.persist(cc);
|
||||
em.flush();
|
||||
claw.setReceptionCostId(cc.getId());
|
||||
lineSum += cc.getTotal();
|
||||
g.setTotal(g.getPlusAmt() + g.getMinusAmt() + lineSum);
|
||||
}
|
||||
|
||||
// ---- 영업점: 송금완료 그룹 ----
|
||||
for (String[] b : branches) {
|
||||
HomesReceptionCostGroup g = new HomesReceptionCostGroup();
|
||||
g.setGroupId("demo");
|
||||
g.setBranchName(b[0]);
|
||||
g.setPlusAmt(0);
|
||||
g.setMinusAmt(0);
|
||||
g.setIsTax(1);
|
||||
g.setRate(BigDecimal.valueOf(10));
|
||||
g.setTaxDate(now.minusDays(8));
|
||||
g.setCompletedAt(now.minusDays(7));
|
||||
g.setTransferredAt(now.minusDays(5));
|
||||
g.setMemo("샘플 송금완료 — " + b[0]);
|
||||
g.setBank("신한");
|
||||
g.setAccountNumber("110-222-" + Math.abs(b[0].hashCode() % 10000));
|
||||
g.setAccountName(b[0]);
|
||||
em.persist(g);
|
||||
em.flush();
|
||||
|
||||
int lineSum = 0;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
HomesReception r = calcReception(
|
||||
"CALC-" + String.format("%04d", seq++),
|
||||
now.minusDays(40 + i), b, carriers[i % 3], products[i % 4],
|
||||
"송금고객" + seq, "f25", "h03", 130000 + i * 7000, true);
|
||||
em.persist(r);
|
||||
em.flush();
|
||||
HomesReceptionCost c = calcCost(r, "i01", 1);
|
||||
c.setCostGroupId(g.getId());
|
||||
em.persist(c);
|
||||
em.flush();
|
||||
r.setReceptionCostId(c.getId());
|
||||
lineSum += c.getTotal();
|
||||
}
|
||||
g.setTotal(lineSum);
|
||||
}
|
||||
|
||||
// ---- 입력처: 가정산 (center cost 없음) — 영업점 대기와 별도 접수 ----
|
||||
for (String[] b : branches) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
HomesReception r = calcReception(
|
||||
"CALC-" + String.format("%04d", seq++),
|
||||
now.minusDays(4 + i), b, carriers[i % 3], products[i % 4],
|
||||
"입력가정산" + seq, "f14", "h01", 90000 + i * 3000, true);
|
||||
// 영업점 정산과는 분리: 개통완료+입력처 정산대기
|
||||
em.persist(r);
|
||||
}
|
||||
HomesReception claw = calcReception(
|
||||
"CALC-" + String.format("%04d", seq++),
|
||||
now.minusDays(18), b, carriers[0], products[0],
|
||||
"입력환수" + seq, "f14", "h05", 60000, true);
|
||||
em.persist(claw);
|
||||
}
|
||||
|
||||
// ---- 입력처: 정산대기 ----
|
||||
for (String[] b : branches) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
HomesReception r = calcReception(
|
||||
"CALC-" + String.format("%04d", seq++),
|
||||
now.minusDays(12 + i), b, carriers[i % 3], products[i % 4],
|
||||
"입력대기" + seq, "f14", "h01", 95000 + i * 4000, true);
|
||||
em.persist(r);
|
||||
em.flush();
|
||||
HomesReceptionCenterCost c = calcCenterCost(r, "k01", 1);
|
||||
em.persist(c);
|
||||
em.flush();
|
||||
r.setReceptionCenterCostId(c.getId());
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 입력처: 정산완료 그룹 ----
|
||||
for (String[] b : branches) {
|
||||
HomesReceptionCenterCostGroup g = new HomesReceptionCenterCostGroup();
|
||||
g.setGroupId("demo");
|
||||
g.setCenterName(b[4]); // processor
|
||||
g.setPlusAmt(3000);
|
||||
g.setMinusAmt(0);
|
||||
g.setIsTax(1);
|
||||
g.setRate(BigDecimal.valueOf(10));
|
||||
g.setCompletedAt(now.minusDays(3));
|
||||
g.setMemo("샘플 입력처 정산완료 — " + b[4]);
|
||||
em.persist(g);
|
||||
em.flush();
|
||||
|
||||
int lineSum = 0;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
HomesReception r = calcReception(
|
||||
"CALC-" + String.format("%04d", seq++),
|
||||
now.minusDays(16 + i), b, carriers[i % 3], products[i % 4],
|
||||
"입력완료" + seq, "f14", "h02", 88000 + i * 2000, true);
|
||||
em.persist(r);
|
||||
em.flush();
|
||||
HomesReceptionCenterCost c = calcCenterCost(r, "k01", 1);
|
||||
c.setCostGroupId(g.getId());
|
||||
em.persist(c);
|
||||
em.flush();
|
||||
r.setReceptionCenterCostId(c.getId());
|
||||
lineSum += c.getTotal();
|
||||
}
|
||||
g.setTotal(g.getPlusAmt() + lineSum);
|
||||
}
|
||||
|
||||
// ---- 입력처: 입금완료 그룹 ----
|
||||
for (String[] b : branches) {
|
||||
HomesReceptionCenterCostGroup g = new HomesReceptionCenterCostGroup();
|
||||
g.setGroupId("demo");
|
||||
g.setCenterName(b[4]);
|
||||
g.setPlusAmt(0);
|
||||
g.setMinusAmt(0);
|
||||
g.setIsTax(1);
|
||||
g.setRate(BigDecimal.valueOf(10));
|
||||
g.setCompletedAt(now.minusDays(9));
|
||||
g.setTransferredAt(now.minusDays(6));
|
||||
g.setMemo("샘플 입금완료 — " + b[4]);
|
||||
em.persist(g);
|
||||
em.flush();
|
||||
|
||||
int lineSum = 0;
|
||||
HomesReception r = calcReception(
|
||||
"CALC-" + String.format("%04d", seq++),
|
||||
now.minusDays(35), b, carriers[0], products[0],
|
||||
"입력입금" + seq, "f14", "h03", 77000, true);
|
||||
em.persist(r);
|
||||
em.flush();
|
||||
HomesReceptionCenterCost c = calcCenterCost(r, "k01", 1);
|
||||
c.setCostGroupId(g.getId());
|
||||
em.persist(c);
|
||||
em.flush();
|
||||
r.setReceptionCenterCostId(c.getId());
|
||||
lineSum += c.getTotal();
|
||||
g.setTotal(lineSum);
|
||||
}
|
||||
|
||||
em.flush();
|
||||
}
|
||||
|
||||
private HomesReception calcReception(
|
||||
String orderNo, LocalDateTime orderDate, String[] branch,
|
||||
String carrier, String product, String customer,
|
||||
String progress, String settle, int amount, boolean opened) {
|
||||
HomesReception r = new HomesReception();
|
||||
r.setGroupId("demo");
|
||||
r.setOrderDate(orderDate);
|
||||
r.setCounselor(branch[3]);
|
||||
r.setBranch(branch[0]);
|
||||
r.setBranchGroup(branch[1]);
|
||||
r.setBranchPhone(branch[5]);
|
||||
r.setRegion(branch[2]);
|
||||
r.setProcessor(branch[4]);
|
||||
r.setCarrier(carrier);
|
||||
r.setIspName(carrier);
|
||||
r.setGiftCategory("상품권");
|
||||
r.setProductCategory("인터넷");
|
||||
r.setProductType("e01");
|
||||
r.setProductName(product);
|
||||
r.setCustomerType("public");
|
||||
r.setCustomerName(customer);
|
||||
r.setPhone("010-" + String.format("%04d", Math.abs(orderNo.hashCode() % 10000)) + "-"
|
||||
+ String.format("%04d", Math.abs(customer.hashCode() % 10000)));
|
||||
r.setProgressStatus(progress);
|
||||
r.setOrderNumber(orderNo);
|
||||
r.setContractNumber(orderNo.replace("CALC-", "CT-"));
|
||||
r.setInboundInfo("서울입고");
|
||||
r.setDetailProgress("정산샘플");
|
||||
r.setPaymentType("현금");
|
||||
r.setPaymentMethod("transfer");
|
||||
r.setAmount(BigDecimal.valueOf(amount));
|
||||
r.setSettleStatus(settle);
|
||||
if (opened) {
|
||||
r.setOpenDate(orderDate.toLocalDate().minusDays(1));
|
||||
r.setGiftDate(orderDate.toLocalDate());
|
||||
r.setGiftStatus("g07");
|
||||
r.setGiftPlace("b01");
|
||||
r.setGiftSended(orderDate.toLocalDate());
|
||||
}
|
||||
r.setAgreementName("36개월");
|
||||
r.setMemo("정산현황 테스트 샘플 (" + progress + "/" + settle + ")");
|
||||
r.setPostIt("");
|
||||
return r;
|
||||
}
|
||||
|
||||
private HomesReceptionCost calcCost(HomesReception r, String type, int sign) {
|
||||
HomesReceptionCost c = new HomesReceptionCost();
|
||||
c.setGroupId("demo");
|
||||
c.setReceptionId(r.getId());
|
||||
c.setType(type);
|
||||
c.setTypeDesc(ReceptionStatuses.COST_TYPE.getOrDefault(type, ""));
|
||||
int base = r.getAmount() == null ? 0 : r.getAmount().intValue();
|
||||
c.setCost(base * sign);
|
||||
c.setEventAmt(0);
|
||||
c.setAgreementAmt(0);
|
||||
c.setLocalAmt(0);
|
||||
// 사은품 차감(본사발송 가정)
|
||||
int gift = ("g07".equals(r.getGiftStatus()) ? -10000 : 0) * sign;
|
||||
c.setGiftAmt(gift);
|
||||
c.setVocAmt(0);
|
||||
c.setEtcAmt(0);
|
||||
c.setTotal(c.getCost() + c.getGiftAmt());
|
||||
c.setMemo("샘플 정산라인");
|
||||
return c;
|
||||
}
|
||||
|
||||
private HomesReceptionCenterCost calcCenterCost(HomesReception r, String type, int sign) {
|
||||
HomesReceptionCenterCost c = new HomesReceptionCenterCost();
|
||||
c.setGroupId("demo");
|
||||
c.setReceptionId(r.getId());
|
||||
c.setType(type);
|
||||
c.setTypeDesc(ReceptionStatuses.CENTER_COST_TYPE.getOrDefault(type, ""));
|
||||
int base = r.getAmount() == null ? 0 : r.getAmount().intValue();
|
||||
// 입력처 수수료는 영업점보다 낮게
|
||||
c.setCost((base / 2) * sign);
|
||||
c.setEventAmt(0);
|
||||
c.setAgreementAmt(0);
|
||||
c.setLocalAmt(0);
|
||||
c.setGiftAmt(0);
|
||||
c.setVocAmt(0);
|
||||
c.setEtcAmt(0);
|
||||
c.setTotal(c.getCost());
|
||||
c.setMemo("샘플 입력처 정산라인");
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* 수수료 현황 팝업 테스트용 — billing_imeere branch_fees / center_fees 샘플.
|
||||
* 서초점·강남점 등은 수수료 있음, 일부 통신사 조합은 없음으로 "적용가능한 수수료가 없습니다" 검증.
|
||||
*/
|
||||
private void seedFeeSheetsIfEmpty() {
|
||||
Long n = em.createQuery("select count(f) from HomesBranchFee f where f.groupId='demo'", Long.class)
|
||||
.getSingleResult();
|
||||
if (n != null && n > 0) return;
|
||||
|
||||
LocalDateTime start = LocalDateTime.of(2024, 1, 1, 0, 0);
|
||||
String[][] branchFees = {
|
||||
{"alone", "강남점", "본사그룹", "KT"},
|
||||
{"alone", "서초점", "본사그룹", "KT"},
|
||||
{"alone", "서초점", "본사그룹", "SKB"},
|
||||
{"alone", "서초점", "본사그룹", "LGU+"},
|
||||
{"alone", "송파점", "동부그룹", "KT"},
|
||||
{"alone", "송파점", "동부그룹", "SKB"},
|
||||
{"group", "", "본사그룹", "KT"},
|
||||
{"group", "", "동부그룹", "SKB"},
|
||||
};
|
||||
Object[][] products = {
|
||||
{"e01", "기가인터넷 1G", 100000},
|
||||
{"e01", "안심 인터넷", 80000},
|
||||
{"e01", "B tv 인터넷", 90000},
|
||||
{"e01", "U+ 인터넷", 95000},
|
||||
{"e03", "B tv 프리미엄", 50000},
|
||||
{"e02", "집전화 스마트", 20000},
|
||||
};
|
||||
|
||||
for (String[] bf : branchFees) {
|
||||
HomesBranchFee fee = new HomesBranchFee();
|
||||
fee.setGroupId("demo");
|
||||
fee.setFeeType(bf[0]);
|
||||
fee.setBranchName(blank(bf[1]) ? null : bf[1]);
|
||||
fee.setBranchGroupName(blank(bf[2]) ? null : bf[2]);
|
||||
fee.setCarrier(bf[3]);
|
||||
fee.setStartDate(start);
|
||||
fee.setMemo("샘플 수수료 (" + bf[0] + "/" + bf[3] + ")");
|
||||
em.persist(fee);
|
||||
em.flush();
|
||||
for (Object[] p : products) {
|
||||
if (!String.valueOf(p[1]).contains(bf[3].substring(0, 1))
|
||||
&& !"KT".equals(bf[3]) && !"e01".equals(p[0])) {
|
||||
// keep most products for all carriers
|
||||
}
|
||||
HomesBranchFeeProduct row = new HomesBranchFeeProduct();
|
||||
row.setGroupId("demo");
|
||||
row.setFeeId(fee.getId());
|
||||
row.setProductType(String.valueOf(p[0]));
|
||||
row.setProductName(String.valueOf(p[1]));
|
||||
row.setFee((Integer) p[2]);
|
||||
em.persist(row);
|
||||
}
|
||||
}
|
||||
|
||||
String[] centers = {"박처리", "최처리", "이처리"};
|
||||
String[] carriers = {"KT", "SKB", "LGU+"};
|
||||
for (String center : centers) {
|
||||
for (String carrier : carriers) {
|
||||
// 최처리+LGU+ 는 의도적으로 제외 → 없음 알림 테스트
|
||||
if ("최처리".equals(center) && "LGU+".equals(carrier)) continue;
|
||||
HomesCenterFee fee = new HomesCenterFee();
|
||||
fee.setGroupId("demo");
|
||||
fee.setCenterName(center);
|
||||
fee.setCarrier(carrier);
|
||||
fee.setStartDate(start);
|
||||
fee.setMemo("샘플 입력처 수수료");
|
||||
em.persist(fee);
|
||||
em.flush();
|
||||
for (Object[] p : products) {
|
||||
HomesCenterFeeProduct row = new HomesCenterFeeProduct();
|
||||
row.setGroupId("demo");
|
||||
row.setFeeId(fee.getId());
|
||||
row.setProductType(String.valueOf(p[0]));
|
||||
row.setProductName(String.valueOf(p[1]));
|
||||
row.setFee(((Integer) p[2]) / 2);
|
||||
em.persist(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
em.flush();
|
||||
}
|
||||
|
||||
/** 영업점관리 목록 — 정산/수수료 샘플과 동일 영업점명 */
|
||||
private void seedBranchesIfEmpty() {
|
||||
Long n = em.createQuery("select count(b) from HomesBranch b where b.groupId='demo'", Long.class)
|
||||
.getSingleResult();
|
||||
if (n != null && n > 0) return;
|
||||
|
||||
HomesBranchGroup g1 = new HomesBranchGroup();
|
||||
g1.setGroupId("demo");
|
||||
g1.setName("본사그룹");
|
||||
g1.setSeq(1);
|
||||
em.persist(g1);
|
||||
HomesBranchGroup g2 = new HomesBranchGroup();
|
||||
g2.setGroupId("demo");
|
||||
g2.setName("동부그룹");
|
||||
g2.setSeq(2);
|
||||
em.persist(g2);
|
||||
em.flush();
|
||||
|
||||
Object[][] rows = {
|
||||
// officeName, name, userid, sido, groupId, level, grant, phone, isTax, hasBiz, email
|
||||
{"강남점", "강남대표", "gangnam", "서울", g1.getId(), 1, 1, "010-1111-1001", 1, true, "gangnam@demo.local"},
|
||||
{"서초점", "서초대표", "seocho", "서울", g1.getId(), 1, 1, "010-2222-1002", 1, false, "seocho@demo.local"},
|
||||
{"송파점", "송파대표", "songpa", "서울", g2.getId(), 1, 1, "010-3333-1003", 0, true, "songpa@demo.local"},
|
||||
{"딜러스", "딜러스", "dealers", "대구", g2.getId(), 1, 1, "010-4444-2001", 1, false, "dealers@demo.local"},
|
||||
{"미승인점", "대기초기", "pending1", "부산", g1.getId(), 1, 0, "010-5555-3001", 1, false, "pending@demo.local"},
|
||||
{"박처리", "박처리", "center_park", "서울", null, 5, 1, "010-6666-4001", 1, false, "park@demo.local"},
|
||||
};
|
||||
for (Object[] r : rows) {
|
||||
HomesBranch b = new HomesBranch();
|
||||
b.setGroupId("demo");
|
||||
b.setOfficeName(String.valueOf(r[0]));
|
||||
b.setName(String.valueOf(r[1]));
|
||||
b.setUserid(String.valueOf(r[2]));
|
||||
b.setPasswordHash(encoder.encode("demo1234"));
|
||||
b.setSido(String.valueOf(r[3]));
|
||||
b.setBranchGroupId(r[4] == null ? null : (Long) r[4]);
|
||||
b.setLevel((Integer) r[5]);
|
||||
b.setGrantFlag((Integer) r[6]);
|
||||
b.setPhone(String.valueOf(r[7]));
|
||||
b.setTel("02-000-" + String.valueOf(r[2]).substring(0, Math.min(4, String.valueOf(r[2]).length())));
|
||||
b.setIsTax((Integer) r[8]);
|
||||
b.setHasBusinessLicense((Boolean) r[9]);
|
||||
b.setEmail(String.valueOf(r[10]));
|
||||
b.setAddress(b.getSido() + " " + b.getOfficeName() + " 1길 1");
|
||||
b.setZipcode("06234");
|
||||
b.setAccountBank("국민은행");
|
||||
b.setAccountNumber("123-456-7890");
|
||||
b.setAccountName(b.getName());
|
||||
if (Integer.valueOf(5).equals(b.getLevel())) {
|
||||
b.setCenterName(b.getOfficeName());
|
||||
}
|
||||
if (b.isHasBusinessLicense()) {
|
||||
b.setLicenseNumber("123-45-67890");
|
||||
b.setLicenseType("도소매");
|
||||
b.setLicenseItem("통신판매");
|
||||
}
|
||||
em.persist(b);
|
||||
}
|
||||
em.flush();
|
||||
}
|
||||
|
||||
private static boolean blank(String s) { return s == null || s.isBlank(); }
|
||||
}
|
||||
|
||||
@@ -456,6 +456,8 @@ class HomesReception extends BaseEntity {
|
||||
String region;
|
||||
/** 진행상황 */
|
||||
String progressStatus;
|
||||
/** 직전 진행상태 (가정산 취소 복원용) */
|
||||
String prevProgressStatus;
|
||||
/** 주문번호 */
|
||||
String orderNumber;
|
||||
/** 연결된 ISP id */
|
||||
@@ -535,6 +537,92 @@ class HomesReception extends BaseEntity {
|
||||
String adminFile1;
|
||||
String adminFile2;
|
||||
String adminFile3;
|
||||
/** 영업점 정산 cost FK (가정산→정산대기 시 연결) */
|
||||
Long receptionCostId;
|
||||
/** 입력처 정산 cost FK */
|
||||
Long receptionCenterCostId;
|
||||
}
|
||||
|
||||
/** 접수별 영업점 정산 비용 — billing order_costs */
|
||||
@Entity @Table(name = "homes_reception_costs") @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor
|
||||
class HomesReceptionCost extends BaseEntity {
|
||||
String type;
|
||||
String typeDesc;
|
||||
Integer cost = 0;
|
||||
Integer eventAmt = 0;
|
||||
Integer agreementAmt = 0;
|
||||
Integer localAmt = 0;
|
||||
Integer giftAmt = 0;
|
||||
Integer vocAmt = 0;
|
||||
Integer etcAmt = 0;
|
||||
Integer total = 0;
|
||||
@Column(columnDefinition = "TEXT") String progressMemo;
|
||||
@Column(columnDefinition = "TEXT") String memo;
|
||||
Long receptionId;
|
||||
Long costGroupId;
|
||||
}
|
||||
|
||||
/** 영업점 정산 그룹 — billing order_cost_groups */
|
||||
@Entity @Table(name = "homes_reception_cost_groups") @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor
|
||||
class HomesReceptionCostGroup extends BaseEntity {
|
||||
String branchName;
|
||||
Integer plusAmt = 0;
|
||||
Integer minusAmt = 0;
|
||||
Integer total = 0;
|
||||
/** 세율(%) — 세금계산서 10 / 종합소득 -3.3 */
|
||||
java.math.BigDecimal rate = java.math.BigDecimal.ZERO;
|
||||
/** 1=세금계산서발행, 0=종합소득세공제 */
|
||||
Integer isTax = 1;
|
||||
LocalDateTime taxDate;
|
||||
LocalDateTime completedAt;
|
||||
LocalDateTime transferredAt;
|
||||
String bank;
|
||||
String accountNumber;
|
||||
String accountName;
|
||||
@Column(columnDefinition = "TEXT") String memo;
|
||||
String file1;
|
||||
String file2;
|
||||
String file3;
|
||||
}
|
||||
|
||||
/** 접수별 입력처 정산 비용 — billing order_center_costs */
|
||||
@Entity @Table(name = "homes_reception_center_costs") @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor
|
||||
class HomesReceptionCenterCost extends BaseEntity {
|
||||
String type;
|
||||
String typeDesc;
|
||||
Integer cost = 0;
|
||||
Integer eventAmt = 0;
|
||||
Integer agreementAmt = 0;
|
||||
Integer localAmt = 0;
|
||||
Integer giftAmt = 0;
|
||||
Integer vocAmt = 0;
|
||||
Integer etcAmt = 0;
|
||||
Integer total = 0;
|
||||
@Column(columnDefinition = "TEXT") String progressMemo;
|
||||
@Column(columnDefinition = "TEXT") String memo;
|
||||
Long receptionId;
|
||||
Long costGroupId;
|
||||
}
|
||||
|
||||
/** 입력처 정산 그룹 — billing order_center_cost_groups */
|
||||
@Entity @Table(name = "homes_reception_center_cost_groups") @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor
|
||||
class HomesReceptionCenterCostGroup extends BaseEntity {
|
||||
String centerName;
|
||||
Integer plusAmt = 0;
|
||||
Integer minusAmt = 0;
|
||||
Integer total = 0;
|
||||
java.math.BigDecimal rate = java.math.BigDecimal.ZERO;
|
||||
Integer isTax = 1;
|
||||
LocalDateTime taxDate;
|
||||
LocalDateTime completedAt;
|
||||
LocalDateTime transferredAt;
|
||||
String bank;
|
||||
String accountNumber;
|
||||
String accountName;
|
||||
@Column(columnDefinition = "TEXT") String memo;
|
||||
String file1;
|
||||
String file2;
|
||||
String file3;
|
||||
}
|
||||
|
||||
/** 접수 진행 이력 */
|
||||
@@ -585,3 +673,168 @@ class HomesReceptionIspAgreement extends BaseEntity {
|
||||
String name;
|
||||
Boolean active;
|
||||
}
|
||||
|
||||
/** 영업점 그룹 — billing branch_groups */
|
||||
@Entity @Table(name = "homes_branch_groups") @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor
|
||||
class HomesBranchGroup extends BaseEntity {
|
||||
String name;
|
||||
Integer seq = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 영업점 마스터 — billing Branch + 상세(계좌/사업자/권한 등)를 한 테이블로 축소.
|
||||
* officeName 은 접수·수수료의 branch / branchName 문자열과 맞춤.
|
||||
*/
|
||||
@Entity @Table(name = "homes_branches") @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor
|
||||
class HomesBranch extends BaseEntity {
|
||||
String name;
|
||||
String officeName;
|
||||
String userid;
|
||||
String passwordHash;
|
||||
String tel;
|
||||
String phone;
|
||||
String fax;
|
||||
String email;
|
||||
String zipcode;
|
||||
String address;
|
||||
String addressDetail;
|
||||
/** 지역(시/도) */
|
||||
String sido;
|
||||
/** 1=영업점, 5=센터, 9=관리자, 10=최고관리자 */
|
||||
Integer level = 1;
|
||||
/** 1=승인, 0=미승인(거부) */
|
||||
Integer grantFlag = 0;
|
||||
Long branchGroupId;
|
||||
/** 레벨=센터일 때 입력처명 */
|
||||
String centerName;
|
||||
boolean hasBusinessLicense = false;
|
||||
Integer isTax = 1;
|
||||
String accountBank;
|
||||
String accountNumber;
|
||||
String accountName;
|
||||
String contactPhone;
|
||||
String contactNateon;
|
||||
Integer acceptPhone = 0;
|
||||
Integer acceptNateon = 0;
|
||||
@Column(columnDefinition = "TEXT") String memo;
|
||||
@Column(columnDefinition = "TEXT") String adminMemo;
|
||||
String licenseNumber;
|
||||
String licenseType;
|
||||
String licenseItem;
|
||||
/** JSON 배열 문자열, 최대 6개 */
|
||||
@Column(columnDefinition = "TEXT") String notifyPhonesJson;
|
||||
boolean permissionOrderDateUpdate = false;
|
||||
boolean permissionCalculate = false;
|
||||
boolean permissionConfig = false;
|
||||
boolean permissionExcelDownload = false;
|
||||
boolean permissionChart = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 영업점 수수료 시트 — billing branch_fees / branch_group_fees 축소.
|
||||
* BillCare는 영업점명을 문자열로 쓰므로 branchName 키.
|
||||
*/
|
||||
@Entity @Table(name = "homes_branch_fees") @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor
|
||||
class HomesBranchFee extends BaseEntity {
|
||||
/** alone=개별, group=그룹 */
|
||||
String feeType;
|
||||
String branchName;
|
||||
String branchGroupName;
|
||||
String carrier;
|
||||
LocalDateTime startDate;
|
||||
@Column(columnDefinition = "TEXT") String memo;
|
||||
/** 첨부 표시용 파일명 (업로드는 선택 구현) */
|
||||
String file1;
|
||||
String file2;
|
||||
String file3;
|
||||
String file4;
|
||||
String file5;
|
||||
}
|
||||
|
||||
@Entity @Table(name = "homes_branch_fee_products") @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor
|
||||
class HomesBranchFeeProduct extends BaseEntity {
|
||||
Long feeId;
|
||||
String productType;
|
||||
String productName;
|
||||
Integer fee = 0;
|
||||
}
|
||||
|
||||
/** 입력처 수수료 시트 — billing center_fees */
|
||||
@Entity @Table(name = "homes_center_fees") @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor
|
||||
class HomesCenterFee extends BaseEntity {
|
||||
String centerName;
|
||||
String carrier;
|
||||
LocalDateTime startDate;
|
||||
@Column(columnDefinition = "TEXT") String memo;
|
||||
}
|
||||
|
||||
@Entity @Table(name = "homes_center_fee_products") @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor
|
||||
class HomesCenterFeeProduct extends BaseEntity {
|
||||
Long feeId;
|
||||
String productType;
|
||||
String productName;
|
||||
Integer fee = 0;
|
||||
}
|
||||
|
||||
/** 통신사 그룹 */
|
||||
@Entity @Table(name="homes_isp_groups") @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor
|
||||
class HomesIspGroup extends BaseEntity {
|
||||
String name;
|
||||
Integer seq = 0;
|
||||
}
|
||||
|
||||
/** 통신사 인증링크 */
|
||||
@Entity @Table(name="homes_isp_links") @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor
|
||||
class HomesIspLink extends BaseEntity {
|
||||
Long ispId;
|
||||
String name;
|
||||
String url;
|
||||
Integer seq = 0;
|
||||
Boolean active = true;
|
||||
}
|
||||
|
||||
/** 입력처(센터) 마스터 — billing Center */
|
||||
@Entity @Table(name="homes_input_centers") @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor
|
||||
class HomesInputCenter extends BaseEntity {
|
||||
String name;
|
||||
String tel;
|
||||
String phone;
|
||||
String manager;
|
||||
Integer seq = 0;
|
||||
Boolean active = true;
|
||||
String accountBank;
|
||||
String accountNumber;
|
||||
String accountName;
|
||||
@Column(columnDefinition="TEXT") String memo;
|
||||
String file1; String file2; String file3; String file4; String file5;
|
||||
}
|
||||
|
||||
/** 게시판 정의 — billing Board (HomesBbs는 게시글) */
|
||||
@Entity @Table(name="homes_boards") @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor
|
||||
class HomesBoard extends BaseEntity {
|
||||
String name;
|
||||
Integer listLevel = 1;
|
||||
Integer readLevel = 1;
|
||||
Integer writeLevel = 9;
|
||||
Integer seq = 0;
|
||||
Boolean active = true;
|
||||
}
|
||||
|
||||
/** 퀵전송 입력처 인증 */
|
||||
@Entity @Table(name="homes_center_quick_auths") @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor
|
||||
class HomesCenterQuickAuth extends BaseEntity {
|
||||
Long centerId;
|
||||
String userid;
|
||||
String passwordEnc;
|
||||
String baseUrl;
|
||||
Boolean authorized = false;
|
||||
}
|
||||
|
||||
/** 퀵전송 진행알림 로그 */
|
||||
@Entity @Table(name="homes_quick_delivery_logs") @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor
|
||||
class HomesQuickDeliveryLog extends BaseEntity {
|
||||
String name;
|
||||
String status;
|
||||
@Column(columnDefinition="TEXT") String memo;
|
||||
Long orderQuickDeliveryClientId;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
package com.bizcare.agent;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* billing_react AppConstant 의 접수/사은품/입력처/정산 상태·전이를 BillCare 에 이식.
|
||||
*/
|
||||
public final class ReceptionStatuses {
|
||||
private ReceptionStatuses() {}
|
||||
|
||||
public static final List<String> PRE_CALC_STATUSES =
|
||||
List.of("f19", "f20", "f21", "f22", "f28", "f23");
|
||||
public static final List<String> CENTER_PRE_CALC_STATUSES =
|
||||
List.of("h01", "h05", "h06", "h07", "h08", "h11");
|
||||
|
||||
public static final Map<String, String> PROGRESS = map(
|
||||
"f01", "접수", "f02", "재접수", "f03", "접수진행중", "f04", "접수완료",
|
||||
"f05", "승인대기중", "f06", "회신요청", "f07", "접수반송", "f08", "미개통오더반송",
|
||||
"f09", "TC실패반송", "f10", "접수보류", "f11", "접수취소", "f12", "개통중",
|
||||
"f13", "기사완료", "f14", "개통완료", "f15", "개통보류", "f16", "개통취소",
|
||||
"f17", "개통불가", "f18", "정산보류", "f19", "위면해지", "f20", "직권해지",
|
||||
"f21", "유보중단환수", "f22", "해지", "f23", "정산대기", "f24", "정산완료",
|
||||
"f25", "송금완료", "f26", "환수정산완료", "f27", "환수완료",
|
||||
"f28", "VOC(귀책)차감", "f29", "VOC(귀책)차감완료");
|
||||
|
||||
public static final Map<String, String> GIFT = map(
|
||||
"g01", "지급요청", "g02", "지급재요청", "g03", "반송", "g04", "처리중",
|
||||
"g05", "지급보류", "g06", "지급취소", "g07", "지급완료", "g08", "회수요청",
|
||||
"g09", "회수(반환)완료", "g10", "등록완료", "g11", "삭제완료", "g12", "입금증요청",
|
||||
"g13", "입금증완료", "g14", "입금증첨부완료", "g15", "입금증(센터)전달완료");
|
||||
|
||||
public static final Map<String, String> CENTER = map(
|
||||
"h01", "정산대기", "h02", "정산완료", "h03", "입금완료", "h04", "정산보류",
|
||||
"h05", "위면해지", "h06", "직권해지", "h07", "유보중단환수", "h08", "해지",
|
||||
"h09", "해지정산완료", "h10", "해지송금완료", "h11", "VOC(귀책)송금", "h12", "VOC(귀책)송금완료");
|
||||
|
||||
public static final Map<String, String> GIFT_PLACE = map(
|
||||
"b02", "자체발송", "b01", "본사발송", "b03", "본사(센터)", "b04", "본사(관리자)");
|
||||
|
||||
public static final Map<String, String> COST_TYPE = map(
|
||||
"i01", "정산", "i02", "위면해지", "i03", "직권해지", "i04", "유보중단환수", "i05", "해지", "i06", "voc차감");
|
||||
|
||||
public static final Map<String, String> CENTER_COST_TYPE = map(
|
||||
"k01", "정산", "k02", "위면해지", "k03", "직권해지", "k04", "유보중단환수", "k05", "해지", "k06", "voc차감");
|
||||
|
||||
/** 구 BillCare 한글 라벨 → 코드 */
|
||||
public static final Map<String, String> LEGACY_PROGRESS = Map.ofEntries(
|
||||
Map.entry("1.접수완료", "f04"),
|
||||
Map.entry("2.고객통화", "f03"),
|
||||
Map.entry("3.서류검토", "f05"),
|
||||
Map.entry("4.개통완료", "f14"),
|
||||
Map.entry("5.사은품지급", "f14"),
|
||||
Map.entry("6.정산완료", "f24"),
|
||||
Map.entry("9.취소", "f11"),
|
||||
Map.entry("접수", "f01"),
|
||||
Map.entry("접수완료", "f04"),
|
||||
Map.entry("개통완료", "f14"),
|
||||
Map.entry("정산대기", "f23"),
|
||||
Map.entry("정산완료", "f24"),
|
||||
Map.entry("송금완료", "f25"),
|
||||
Map.entry("접수취소", "f11")
|
||||
);
|
||||
|
||||
public static final Map<String, String> LEGACY_GIFT = Map.of(
|
||||
"미지급", "",
|
||||
"지급대기", "g01",
|
||||
"지급요청", "g01",
|
||||
"지급완료", "g07",
|
||||
"반송", "g03"
|
||||
);
|
||||
|
||||
public static final Map<String, String> LEGACY_CENTER = Map.of(
|
||||
"정산대기", "h01",
|
||||
"정산완료", "h02",
|
||||
"입금완료", "h03",
|
||||
"회수대기", "h05",
|
||||
"회수완료", "h09",
|
||||
"미지정", "h01"
|
||||
);
|
||||
|
||||
public static List<String> progressCodes() {
|
||||
return new ArrayList<>(PROGRESS.keySet());
|
||||
}
|
||||
|
||||
public static List<String> giftCodes() {
|
||||
return new ArrayList<>(GIFT.keySet());
|
||||
}
|
||||
|
||||
public static List<String> centerCodes() {
|
||||
return new ArrayList<>(CENTER.keySet());
|
||||
}
|
||||
|
||||
public static String progressLabel(String code) {
|
||||
if (code == null || code.isBlank()) return "";
|
||||
return PROGRESS.getOrDefault(code, code);
|
||||
}
|
||||
|
||||
public static String giftLabel(String code) {
|
||||
if (code == null || code.isBlank()) return "";
|
||||
return GIFT.getOrDefault(code, code);
|
||||
}
|
||||
|
||||
public static String centerLabel(String code) {
|
||||
if (code == null || code.isBlank()) return "";
|
||||
return CENTER.getOrDefault(code, code);
|
||||
}
|
||||
|
||||
public static String normalizeProgress(String raw) {
|
||||
if (raw == null || raw.isBlank()) return "";
|
||||
if (PROGRESS.containsKey(raw)) return raw;
|
||||
return LEGACY_PROGRESS.getOrDefault(raw, raw);
|
||||
}
|
||||
|
||||
public static String normalizeGift(String raw) {
|
||||
if (raw == null) return "";
|
||||
if (raw.isBlank() || "미지급".equals(raw)) return "";
|
||||
if (GIFT.containsKey(raw)) return raw;
|
||||
return LEGACY_GIFT.getOrDefault(raw, raw);
|
||||
}
|
||||
|
||||
public static String normalizeCenter(String raw) {
|
||||
if (raw == null || raw.isBlank()) return "";
|
||||
if (CENTER.containsKey(raw)) return raw;
|
||||
return LEGACY_CENTER.getOrDefault(raw, raw);
|
||||
}
|
||||
|
||||
public static Set<String> orderStatusTransitions(String current) {
|
||||
if (current == null) return Set.of();
|
||||
return switch (current) {
|
||||
case "f01", "f02", "f03", "f04", "f05", "f06", "f07", "f08", "f09", "f10", "f11", "f12",
|
||||
"f13", "f15", "f16", "f17" ->
|
||||
set("f01", "f02", "f03", "f04", "f05", "f06", "f07", "f08", "f09",
|
||||
"f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18");
|
||||
case "f18", "f14" ->
|
||||
set("f01", "f02", "f03", "f04", "f05", "f06", "f07", "f08", "f09",
|
||||
"f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18",
|
||||
"f19", "f20", "f21", "f22", "f23");
|
||||
case "f23" -> set("f23");
|
||||
case "f24" -> set("f24");
|
||||
case "f25" -> set("f25", "f19", "f20", "f21", "f22", "f28");
|
||||
case "f19" -> set("f19");
|
||||
case "f20" -> set("f20");
|
||||
case "f21" -> set("f21");
|
||||
case "f22" -> set("f22");
|
||||
case "f28" -> set("f28");
|
||||
case "f29" -> set("f28", "f29", "f19", "f20", "f21", "f22");
|
||||
case "f26" -> set("f26");
|
||||
case "f27" -> set("f27");
|
||||
default -> Set.of();
|
||||
};
|
||||
}
|
||||
|
||||
public static Set<String> centerStatusTransitions(String current) {
|
||||
if (current == null || current.isBlank()) return set("h01");
|
||||
return switch (current) {
|
||||
case "h01" -> set("h01");
|
||||
case "h02" -> set("h02");
|
||||
case "h03" -> set("h03", "h05", "h06", "h07", "h08", "h11");
|
||||
case "h04" -> set("h04", "h01");
|
||||
case "h05" -> set("h05");
|
||||
case "h06" -> set("h06");
|
||||
case "h07" -> set("h07");
|
||||
case "h08" -> set("h08");
|
||||
case "h09" -> set("h09");
|
||||
case "h10" -> set("h10");
|
||||
case "h11" -> set("h11");
|
||||
case "h12" -> set("h05", "h06", "h07", "h08", "h11");
|
||||
default -> Set.of();
|
||||
};
|
||||
}
|
||||
|
||||
public static String orderCostType(String orderStatus) {
|
||||
if (orderStatus == null) return "";
|
||||
return switch (orderStatus) {
|
||||
case "f19" -> "i02";
|
||||
case "f20" -> "i03";
|
||||
case "f21" -> "i04";
|
||||
case "f22" -> "i05";
|
||||
case "f28" -> "i06";
|
||||
case "f23" -> "i01";
|
||||
default -> "";
|
||||
};
|
||||
}
|
||||
|
||||
public static String centerCostType(String status) {
|
||||
if (status == null) return "";
|
||||
return switch (status) {
|
||||
case "h05" -> "k02";
|
||||
case "h06" -> "k03";
|
||||
case "h07" -> "k04";
|
||||
case "h08" -> "k05";
|
||||
case "h11" -> "k06";
|
||||
case "h01" -> "k01";
|
||||
default -> "";
|
||||
};
|
||||
}
|
||||
|
||||
public static boolean isPreCalc(String status) {
|
||||
return status != null && PRE_CALC_STATUSES.contains(status);
|
||||
}
|
||||
|
||||
public static boolean isCenterPreCalc(String status) {
|
||||
return status != null && CENTER_PRE_CALC_STATUSES.contains(status);
|
||||
}
|
||||
|
||||
private static Map<String, String> map(String... kv) {
|
||||
Map<String, String> m = new LinkedHashMap<>();
|
||||
for (int i = 0; i < kv.length; i += 2) m.put(kv[i], kv[i + 1]);
|
||||
return Collections.unmodifiableMap(m);
|
||||
}
|
||||
|
||||
private static Set<String> set(String... v) {
|
||||
return new LinkedHashSet<>(Arrays.asList(v));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user