// Path: micro-asset/src/main/java/sample/microasset/model/asset/type/CashflowType.java
// public enum CashflowType {
//     /** 振込入金 */
//     CashIn,
//     /** 振込出金 */
//     CashOut,
//     /** 振替入金 */
//     CashTransferIn,
//     /** 振替出金 */
//     CashTransferOut
// }


import java.math.BigDecimal;
import java.time.*;
import java.util.List;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import lombok.*;
import sample.ActionStatusType;
import sample.ValidationException.ErrorKeys;
import sample.context.Dto;
import sample.context.orm.*;
import sample.microasset.model.asset.type.CashflowType;
import sample.model.constraints.*;
import sample.util.*;
package sample.microasset.model.asset;




/**
 * 入出金キャッシュフローを表現します。
 * キャッシュフローは振込/振替といったキャッシュフローアクションから生成される確定状態(依頼取消等の無い)の入出金情報です。
 * low: 概念を伝えるだけなので必要最低限の項目で表現しています。
 * low: 検索関連は主に経理確認や帳票等での利用を想定します
 */
@Entity
@Data
@EqualsAndHashCode(callSuper = false)
public class Cashflow extends OrmActiveMetaRecord<Cashflow> {
    private static final long serialVersionUID = 1L;

    /** ID */
    @Id
    @GeneratedValue
    private Long id;
    /** 口座ID */
    @IdStr
    private String accountId;
    /** 通貨 */
    @Currency
    private String currency;
    /** 金額 */
    @Amount
    private BigDecimal amount;
    /** 入出金 */
    @NotNull
    @Enumerated(EnumType.STRING)
    private CashflowType cashflowType;
    /** 摘要 */
    @Category
    private String remark;
    /** 発生日/日時 */
    @ISODate
    private LocalDate eventDay;
    @ISODateTime
    private LocalDateTime eventDate;
    /** 受渡日 */
    @ISODate
    private LocalDate valueDay;
    /** 処理種別 */
    @NotNull
    @Enumerated(EnumType.STRING)
    private ActionStatusType statusType;
    /** 登録日時 */
    @ISODateTime
    private LocalDateTime createDate;
    /** 登録者ID */
    @IdStr
    private String createId;
    /** 更新日時 */
    @ISODateTime
    private LocalDateTime updateDate;
    /** 更新者ID */
    @IdStr
    private String updateId;

    /** キャッシュフローを処理済みにして残高へ反映します。 */
    public Cashflow realize(final OrmRepository rep) {
        validate((v) -> {
            v.verify(canRealize(rep), AssetErrorKeys.CashflowRealizeDay);
            v.verify(statusType.isUnprocessing(), ErrorKeys.ActionUnprocessing); // 「既に処理中/処理済です」
        });

        setStatusType(ActionStatusType.Processed);
        update(rep);
        CashBalance.getOrNew(rep, accountId, currency).add(rep, amount);
        return this;
    }

    /**
     * キャッシュフローをエラー状態にします。
     * <p>処理中に失敗した際に呼び出してください。
     * low: 実際はエラー事由などを引数に取って保持する
     */
    public Cashflow error(final OrmRepository rep) {
        validate((v) -> v.verify(statusType.isUnprocessed(), ErrorKeys.ActionUnprocessing));

        setStatusType(ActionStatusType.Error);
        return update(rep);
    }

    /** キャッシュフローを実現(受渡)可能か判定します。 */
    public boolean canRealize(final OrmRepository rep) {
        return rep.dh().time().tp().afterEqualsDay(valueDay);
    }

    /** キャッシュフローを取得します。(例外付) */
    public static Cashflow load(final OrmRepository rep, Long id) {
        return rep.load(Cashflow.class, id);
    }

    /**
     * 指定受渡日時点で未実現のキャッシュフロー一覧を検索します。(口座通貨別)
     */
    public static List<Cashflow> findUnrealize(final OrmRepository rep, String accountId, String currency,
            LocalDate valueDay) {
// Path: micro-asset/src/main/java/sample/microasset/model/asset/type/CashflowType.java
// public enum CashflowType {
//     /** 振込入金 */
//     CashIn,
//     /** 振込出金 */
//     CashOut,
//     /** 振替入金 */
//     CashTransferIn,
//     /** 振替出金 */
//     CashTransferOut
// }


// Path: micro-asset/src/main/java/sample/microasset/model/asset/Cashflow.java
import java.math.BigDecimal;
import java.time.*;
import java.util.List;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import lombok.*;
import sample.ActionStatusType;
import sample.ValidationException.ErrorKeys;
import sample.context.Dto;
import sample.context.orm.*;
import sample.microasset.model.asset.type.CashflowType;
import sample.model.constraints.*;
import sample.util.*;

package sample.microasset.model.asset;




/**
 * 入出金キャッシュフローを表現します。
 * キャッシュフローは振込/振替といったキャッシュフローアクションから生成される確定状態(依頼取消等の無い)の入出金情報です。
 * low: 概念を伝えるだけなので必要最低限の項目で表現しています。
 * low: 検索関連は主に経理確認や帳票等での利用を想定します
 */
@Entity
@Data
@EqualsAndHashCode(callSuper = false)
public class Cashflow extends OrmActiveMetaRecord<Cashflow> {
    private static final long serialVersionUID = 1L;

    /** ID */
    @Id
    @GeneratedValue
    private Long id;
    /** 口座ID */
    @IdStr
    private String accountId;
    /** 通貨 */
    @Currency
    private String currency;
    /** 金額 */
    @Amount
    private BigDecimal amount;
    /** 入出金 */
    @NotNull
    @Enumerated(EnumType.STRING)
    private CashflowType cashflowType;
    /** 摘要 */
    @Category
    private String remark;
    /** 発生日/日時 */
    @ISODate
    private LocalDate eventDay;
    @ISODateTime
    private LocalDateTime eventDate;
    /** 受渡日 */
    @ISODate
    private LocalDate valueDay;
    /** 処理種別 */
    @NotNull
    @Enumerated(EnumType.STRING)
    private ActionStatusType statusType;
    /** 登録日時 */
    @ISODateTime
    private LocalDateTime createDate;
    /** 登録者ID */
    @IdStr
    private String createId;
    /** 更新日時 */
    @ISODateTime
    private LocalDateTime updateDate;
    /** 更新者ID */
    @IdStr
    private String updateId;

    /** キャッシュフローを処理済みにして残高へ反映します。 */
    public Cashflow realize(final OrmRepository rep) {
        validate((v) -> {
            v.verify(canRealize(rep), AssetErrorKeys.CashflowRealizeDay);
            v.verify(statusType.isUnprocessing(), ErrorKeys.ActionUnprocessing); // 「既に処理中/処理済です」
        });

        setStatusType(ActionStatusType.Processed);
        update(rep);
        CashBalance.getOrNew(rep, accountId, currency).add(rep, amount);
        return this;
    }

    /**
     * キャッシュフローをエラー状態にします。
     * <p>処理中に失敗した際に呼び出してください。
     * low: 実際はエラー事由などを引数に取って保持する
     */
    public Cashflow error(final OrmRepository rep) {
        validate((v) -> v.verify(statusType.isUnprocessed(), ErrorKeys.ActionUnprocessing));

        setStatusType(ActionStatusType.Error);
        return update(rep);
    }

    /** キャッシュフローを実現(受渡)可能か判定します。 */
    public boolean canRealize(final OrmRepository rep) {
        return rep.dh().time().tp().afterEqualsDay(valueDay);
    }

    /** キャッシュフローを取得します。(例外付) */
    public static Cashflow load(final OrmRepository rep, Long id) {
        return rep.load(Cashflow.class, id);
    }

    /**
     * 指定受渡日時点で未実現のキャッシュフロー一覧を検索します。(口座通貨別)
     */
    public static List<Cashflow> findUnrealize(final OrmRepository rep, String accountId, String currency,
            LocalDate valueDay) {
        return rep.tmpl().find(