/* * 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.po; import com.rockagen.gnext.enums.AccountStatus; import com.rockagen.gnext.enums.AccountType; import com.rockagen.gnext.enums.ErrorType; import com.rockagen.gnext.exception.AccountException; import javax.persistence.*; import java.math.BigDecimal; import java.util.Date; import java.util.Optional; /** * Account * @author ra * @since JDK1.8 */ @Entity @Table(name = "ACCOUNTS") public class Account { @Id @Column(name = "ID") @GeneratedValue private Long id; @Enumerated(EnumType.STRING) @Column(name = "STATUS",nullable=false) private AccountStatus status; @Enumerated(EnumType.STRING) @Column(name = "TYPE", nullable = false) private AccountType type; /** * The priority. the smaller the value the higher the priority */ @Column(name = "PRIORITY") private Integer priority; @Column(name = "ENABLED_AT") private Date enabledAt; @Column(name = "LOCKED_AT") private Date lockedAt; @Column(name = "EXPIRED_AT") private Date expiredAt; @Column(name = "INVALID_AT") private Date invalidAt; @Column(name = "CREATED_AT",nullable = false) private Date createdAt; @Column(name = "UPDATED_AT") private Date updatedAt; @Column(name = "BALANCE",precision=16,scale = 8) private BigDecimal balance; @Column(name = "AVAILABLE_BALANCE",precision=16,scale = 8) private BigDecimal availableBalance; @Column(name = "LOCKED_BALANCE",precision=16,scale = 8) private BigDecimal lockedBalance; @Column(name = "REMARK") private String remark; @ManyToOne(cascade = CascadeType.MERGE) @JoinColumn(name = "USER_ID",nullable = false) private AuthUser user; @Version private Long version; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public AccountStatus getStatus() { return status; } public void setStatus(AccountStatus status) { this.status = status; } public AccountType getType() { return type; } public void setType(AccountType type) { this.type = type; } public Date getEnabledAt() { return enabledAt; } public void setEnabledAt(Date enabledAt) { this.enabledAt = enabledAt; } public Date getLockedAt() { return lockedAt; } public void setLockedAt(Date lockedAt) { this.lockedAt = lockedAt; } public Date getExpiredAt() { return expiredAt; } public void setExpiredAt(Date expiredAt) { this.expiredAt = expiredAt; } public Date getInvalidAt() { return invalidAt; } public void setInvalidAt(Date invalidAt) { this.invalidAt = invalidAt; } public Date getCreatedAt() { return createdAt; } public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; } public Date getUpdatedAt() { return updatedAt; } public void setUpdatedAt(Date updatedAt) { this.updatedAt = updatedAt; } public BigDecimal getBalance() { return balance; } public void setBalance(BigDecimal balance) { this.balance = balance; } public BigDecimal getAvailableBalance() { return availableBalance; } public void setAvailableBalance(BigDecimal availableBalance) { this.availableBalance = availableBalance; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } public AuthUser getUser() { return user; } public void setUser(AuthUser user) { this.user = user; } public Long getVersion() { return version; } public void setVersion(Long version) { this.version = version; } public Integer getPriority() { return priority; } public void setPriority(Integer priority) { this.priority = priority; } public BigDecimal getLockedBalance() { return lockedBalance; } public void setLockedBalance(BigDecimal lockedBalance) { this.lockedBalance = lockedBalance; } /** * Add balance * @param amount amount */ public void addBalance(BigDecimal amount){ if(amount!=null){ balanceCheck(); balance=balance.add(amount.abs()); balanceChange(); } } /** * Sub balance * @param amount amount */ public void subtractBalance(BigDecimal amount) throws AccountException { if(amount!=null){ if(status!=AccountStatus.OPEN){ throw new AccountException(genErrorTypeByStatus(status)); } balanceCheck(); BigDecimal tmp=availableBalance.subtract(amount.abs()); // 余额不足 if((tmp.compareTo(BigDecimal.ZERO))<0){ throw new AccountException(ErrorType.ACC0010); } balance=balance.subtract(amount.abs()); balanceChange(); } } /** * Locked balance * @param amount amount */ public void lockedBalance(BigDecimal amount) throws AccountException { if(amount!=null){ balanceCheck(); BigDecimal tmp=availableBalance.subtract(amount.abs()); // Balance not enough if((tmp.compareTo(BigDecimal.ZERO))<0){ throw new AccountException(ErrorType.ACC0010); } lockedBalance=lockedBalance.add(amount.abs()); balanceChange(); } } /** * Unlocked balance * @param amount amount */ public void unLockedBalance(BigDecimal amount) throws AccountException { if(amount!=null){ balanceCheck(); BigDecimal tmp=lockedBalance.subtract(amount.abs()); // Balance not enough if((tmp.compareTo(BigDecimal.ZERO))<0){ throw new AccountException(ErrorType.ACC0011); } lockedBalance=lockedBalance.subtract(amount.abs()); balanceChange(); } } private void balanceCheck(){ if(balance==null){ initAccount(); } } private void initAccount(){ balance=BigDecimal.ZERO; availableBalance=BigDecimal.ZERO; lockedBalance=BigDecimal.ZERO; priority=20; } /** * Initialize */ public void init(){ Date date=new Date(); createdAt=date; status=AccountStatus.OPEN; initAccount(); } /** * Balance change notice */ private void balanceChange(){ availableBalance=balance.subtract(lockedBalance); updatedAt=new Date(); } private ErrorType genErrorTypeByStatus(AccountStatus status) { ErrorType et; switch (Optional.ofNullable(status).orElse(AccountStatus.INVALID)) { case LOCKED: et = ErrorType.ACC0020; break; case EXPIRED: et = ErrorType.ACC0021; break; case INVALID: et = ErrorType.ACC0022; break; default: et=ErrorType.ACC0001; } return et; } }