/*
* Copyright 2014-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.rockagen.gnext.service.spring;
import com.rockagen.commons.util.CommUtil;
import com.rockagen.gnext.enums.AccountOperationType;
import com.rockagen.gnext.enums.AccountStatus;
import com.rockagen.gnext.enums.AccountType;
import com.rockagen.gnext.exception.AccountException;
import com.rockagen.gnext.po.Account;
import com.rockagen.gnext.po.AccountBill;
import com.rockagen.gnext.po.AuthUser;
import com.rockagen.gnext.qo.QueryObject;
import com.rockagen.gnext.service.AccountBillServ;
import com.rockagen.gnext.service.AccountServ;
import com.rockagen.gnext.service.AuthUserServ;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Optional;
/**
* Implementation of the {@link AccountServ} interface
*
* @author ra
* @since JDK1.8
*/
@Service("accountServ")
public class AccountServImpl extends QueryObjectGenericServImpl<Account, Long> implements AccountServ {
@Resource
private AccountBillServ accountBillServ;
@Resource
private AuthUserServ authUserServ;
@Override
public Optional<Account> loadByUid(long uid) {
List<Account> list = loadListByUid(uid);
return filter(list);
}
/**
* Offer the maximum priority of the list.
*
* @param list list
* @return Account
*/
private Optional<Account> filter(List<Account> list) {
Account tmp=list.get(0);
if(list.size()>1) {
tmp = list.stream().filter(x -> x.getStatus() == AccountStatus.OPEN)
.min((a, b) -> a.getPriority().compareTo(b.getPriority())).get();
}
return Optional.ofNullable(tmp);
}
@Override
public List<Account> loadListByUid(long uid) {
QueryObject qo = new QueryObject();
DetachedCriteria dc = qo.generateDetachedCriteria(Account.class);
dc.createAlias("user", "u");
dc.add(Restrictions.eq("u.id", uid));
dc.addOrder(Order.desc("updatedAt"));
return find(qo);
}
@Override
public void newAccount(long uid, AccountType type) {
Optional<AuthUser> u = authUserServ.load(uid);
if (u.isPresent()) {
Account a = initAccount(u.get(), type);
add(a);
}
}
@Override
public Optional<Account> loadByUid(String uid) {
Optional<AuthUser> u = authUserServ.load(uid);
if (u.isPresent()) {
return loadByUid(u.get().getId());
} else {
return Optional.empty();
}
}
@Override
public List<Account> loadListByUid(String uid) {
Optional<AuthUser> u = authUserServ.load(uid);
if (u.isPresent()) {
return loadListByUid(u.get().getId());
}
return Collections.emptyList();
}
@Override
public void newAccount(String uid, AccountType type) {
Optional<AuthUser> u = authUserServ.load(uid);
if (u.isPresent()) {
newAccount(u.get().getId(), type);
}
}
/**
* Initialize account*
*
* @param user user
* @param type type
* @return Account
*/
private Account initAccount(AuthUser user, AccountType type) {
Account a = new Account();
a.init();
a.setType(Optional.ofNullable(type).orElse(AccountType.INDIVIDUAL));
a.setUser(user);
a.setRemark(user.getName());
return a;
}
@Override
public void increase(long id, BigDecimal amount, String remark) {
load(id).ifPresent(acc -> {
// account
BigDecimal before = acc.getBalance();
acc.addBalance(amount);
genAccountBill(acc, AccountOperationType.DEBIT, before, amount, remark);
});
}
@Override
public void decrease(long id, BigDecimal amount, String remark) throws AccountException {
Optional<Account> acc = load(id);
if (acc.isPresent()) {
// account
BigDecimal before = acc.get().getBalance();
acc.get().subtractBalance(amount);
genAccountBill(acc.get(), AccountOperationType.CREDIT, before, amount, remark);
}
}
@Override
public void preTakeAmount(long id, BigDecimal amount, String remark) throws AccountException {
lockedBalance(id, amount);
}
@Override
public void takePreAmount(long id, BigDecimal amount, String remark) throws AccountException {
unLockedBalance(id, amount);
decrease(id, amount, remark);
}
@Override
public boolean checkBalance(long id, BigDecimal amount) {
Optional<Account> account = load(id);
if (account.isPresent()) {
return checkBalance(account.get(), amount);
}
return false;
}
@Override
public boolean checkBalance(String uid, BigDecimal amount) {
Optional<Account> account = loadByUid(uid);
if (account.isPresent()) {
return checkBalance(account.get(), amount);
}
return false;
}
@Override
public void lockedBalance(long id, BigDecimal amount) throws AccountException {
Optional<Account> acc = load(id);
if (acc.isPresent()) {
// account
acc.get().lockedBalance(amount);
}
}
@Override
public void unLockedBalance(long id, BigDecimal amount) throws AccountException {
Optional<Account> acc = load(id);
if (acc.isPresent()) {
// account
acc.get().unLockedBalance(amount);
}
}
@Override
public void lockedAccount(long id) {
load(id).ifPresent(acc -> {
// account
Date now = new Date();
acc.setStatus(AccountStatus.LOCKED);
acc.setLockedAt(now);
acc.setUpdatedAt(now);
});
}
@Override
public void unLockedAccount(long id) {
load(id).ifPresent(acc -> {
// account
Date now = new Date();
acc.setStatus(AccountStatus.OPEN);
acc.setEnabledAt(now);
acc.setUpdatedAt(now);
});
}
@Override
public void expiredAccount(long id) {
load(id).ifPresent(acc -> {
// account
Date now = new Date();
acc.setStatus(AccountStatus.EXPIRED);
acc.setExpiredAt(now);
acc.setUpdatedAt(now);
});
}
@Override
public void invalidAccount(long id) {
load(id).ifPresent(acc -> {
// account
Date now = new Date();
acc.setStatus(AccountStatus.INVALID);
acc.setInvalidAt(now);
acc.setUpdatedAt(now);
});
}
/**
* Balance enough?
*
* @param account Account
* @param amount amount
* @return true if enough
*/
private boolean checkBalance(Account account, BigDecimal amount) {
BigDecimal tmp = account.getAvailableBalance().subtract(amount.abs());
if ((tmp.compareTo(BigDecimal.ZERO)) < 0) {
return false;
}
return true;
}
/**
* Account bill
*
* @param po po
* @param amount before balance
* @param amount amount
* @param remark remark
*/
private void genAccountBill(Account po, AccountOperationType opType, BigDecimal beforeBalance, BigDecimal amount, String remark) {
// account bill
Date now = new Date();
AccountBill ab = new AccountBill();
ab.setRemark(remark);
ab.setAccount(po);
ab.setAmount(amount.abs());
ab.setCreatedAt(now);
ab.setOperationType(opType);
ab.setBeforeBalance(beforeBalance);
ab.setAfterBalance(po.getBalance());
ab.setSn(getBillSn(po.getUser().getId()));
accountBillServ.add(ab);
}
private String getBillSn(long uid) {
Date now = new Date();
String tmp = CommUtil.dateTime2StringFS(now);
StringBuilder sb = new StringBuilder(tmp);
String suid = String.format("%08d", uid);
sb.insert(8, suid);
return sb.toString();
}
}