package sample.model.asset; import java.math.*; import java.time.*; import java.util.Optional; import javax.persistence.*; import lombok.*; import sample.context.orm.*; import sample.model.constraints.*; import sample.util.*; /** * 口座残高を表現します。 */ @Entity @Data @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(callSuper = false) public class CashBalance extends OrmActiveRecord<CashBalance> { private static final long serialVersionUID = 1L; /** ID */ @Id @GeneratedValue private Long id; /** 口座ID */ @IdStr private String accountId; /** 基準日 */ @ISODate private LocalDate baseDay; /** 通貨 */ @Currency private String currency; /** 金額 */ @Amount private BigDecimal amount; /** 更新日 */ @ISODateTime private LocalDateTime updateDate; /** * 残高へ指定した金額を反映します。 * low ここではCurrencyを使っていますが、実際の通貨桁数や端数処理定義はDBや設定ファイル等で管理されます。 */ public CashBalance add(final OrmRepository rep, BigDecimal addAmount) { int scale = java.util.Currency.getInstance(currency).getDefaultFractionDigits(); RoundingMode mode = RoundingMode.DOWN; setAmount(Calculator.of(amount).scale(scale, mode).add(addAmount).decimal()); return update(rep); } /** * 指定口座の残高を取得します。(存在しない時は繰越保存後に取得します) * low: 複数通貨の適切な考慮や細かい審査は本筋でないので割愛。 */ public static CashBalance getOrNew(final OrmRepository rep, String accountId, String currency) { LocalDate baseDay = rep.dh().time().day(); Optional<CashBalance> m = rep.tmpl().get( "from CashBalance c where c.accountId=?1 and c.currency=?2 and c.baseDay=?3 order by c.baseDay desc", accountId, currency, baseDay); return m.orElseGet(() -> create(rep, accountId, currency)); } private static CashBalance create(final OrmRepository rep, String accountId, String currency) { TimePoint now = rep.dh().time().tp(); Optional<CashBalance> m = rep.tmpl().get( "from CashBalance c where c.accountId=?1 and c.currency=?2 order by c.baseDay desc", accountId, currency); if (m.isPresent()) { // 残高繰越 CashBalance prev = m.get(); return new CashBalance(null, accountId, now.getDay(), currency, prev.getAmount(), now.getDate()).save(rep); } else { return new CashBalance(null, accountId, now.getDay(), currency, BigDecimal.ZERO, now.getDate()).save(rep); } } }