001// --------------------------------------------------------------------------------
002// Copyright 2002-2024 Echo Three, LLC
003//
004// Licensed under the Apache License, Version 2.0 (the "License");
005// you may not use this file except in compliance with the License.
006// You may obtain a copy of the License at
007//
008//     http://www.apache.org/licenses/LICENSE-2.0
009//
010// Unless required by applicable law or agreed to in writing, software
011// distributed under the License is distributed on an "AS IS" BASIS,
012// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013// See the License for the specific language governing permissions and
014// limitations under the License.
015// --------------------------------------------------------------------------------
016
017package com.echothree.model.control.accounting.server.logic;
018
019import com.echothree.model.control.accounting.server.control.AccountingControl;
020import com.echothree.model.control.core.server.control.CoreControl;
021import com.echothree.model.control.party.server.control.PartyControl;
022import com.echothree.model.data.accounting.server.entity.Currency;
023import com.echothree.model.data.accounting.server.entity.GlAccount;
024import com.echothree.model.data.accounting.server.entity.Transaction;
025import com.echothree.model.data.accounting.server.entity.TransactionDetail;
026import com.echothree.model.data.accounting.server.entity.TransactionEntityRole;
027import com.echothree.model.data.accounting.server.entity.TransactionEntityRoleType;
028import com.echothree.model.data.accounting.server.entity.TransactionGlAccount;
029import com.echothree.model.data.accounting.server.entity.TransactionGlAccountCategory;
030import com.echothree.model.data.accounting.server.entity.TransactionGlEntry;
031import com.echothree.model.data.accounting.server.entity.TransactionStatus;
032import com.echothree.model.data.accounting.server.entity.TransactionType;
033import com.echothree.model.data.core.server.entity.EntityInstance;
034import com.echothree.model.data.party.server.entity.Party;
035import com.echothree.util.common.persistence.BasePK;
036import com.echothree.util.server.persistence.Session;
037
038public class TransactionLogic {
039
040    private TransactionLogic() {
041        super();
042    }
043
044    private static class TransactionLogicHolder {
045        static TransactionLogic instance = new TransactionLogic();
046    }
047
048    public static TransactionLogic getInstance() {
049        return TransactionLogicHolder.instance;
050    }
051    
052    public Transaction createTransactionUsingNames(final Session session, final Party groupParty, final String transactionTypeName, final Long postingTime, final BasePK createdBy) {
053        var accountingControl = Session.getModelController(AccountingControl.class);
054        
055        return createTransaction(session, groupParty, accountingControl.getTransactionTypeByName(transactionTypeName), postingTime, createdBy);
056    }
057    
058    public Transaction createTransaction(final Session session, final Party groupParty, final TransactionType transactionType, final Long postingTime, final BasePK createdBy) {
059        var accountingControl = Session.getModelController(AccountingControl.class);
060        
061        return accountingControl.createTransaction(groupParty, transactionType, postingTime == null? session.START_TIME_LONG: postingTime, createdBy);
062    }
063    
064    public TransactionGlEntry createTransactionGlEntryUsingNames(final Transaction transaction, final Party groupParty, final String transactionGlAccountCategoryName,
065            final GlAccount glAccount, final Currency originalCurrency, final Long originalAmount, final BasePK createdBy) {
066        var accountingControl = Session.getModelController(AccountingControl.class);
067        TransactionDetail transactionDetail = transaction.getLastDetail();
068        
069        return createTransactionGlEntry(transaction, groupParty == null? transactionDetail.getGroupParty(): groupParty,
070                accountingControl.getTransactionGlAccountCategoryByName(transactionDetail.getTransactionType(), transactionGlAccountCategoryName), glAccount, originalCurrency, originalAmount,
071                createdBy);
072    }
073    
074    private GlAccount getGlAccount(final AccountingControl accountingControl, final TransactionGlAccountCategory transactionGlAccountCategory, GlAccount glAccount) {
075        if(glAccount == null) {
076            TransactionGlAccount transactionGlAccount = accountingControl.getTransactionGlAccount(transactionGlAccountCategory);
077            
078            if(transactionGlAccount == null) {
079                throw new IllegalArgumentException("glAccount is a required parameter");
080            } else {
081                glAccount = transactionGlAccount.getGlAccount();
082            }
083        }
084        
085        return glAccount;
086    }
087    
088    private Integer getTransactionGlEntrySequence(final AccountingControl accountingControl, final Transaction transaction) {
089        TransactionStatus transactionStatus = accountingControl.getTransactionStatusForUpdate(transaction);
090        Integer transactionGlEntrySequence = transactionStatus.getTransactionGlEntrySequence() + 1;
091        
092        transactionStatus.setTransactionGlEntrySequence(transactionGlEntrySequence);
093        
094        return transactionGlEntrySequence;
095    }
096    
097    private Long getAmount(final GlAccount glAccount, final Currency originalCurrency, final Long originalAmount) {
098        Currency currency = glAccount.getLastDetail().getCurrency();
099        
100        Long amount = null;
101        if(originalCurrency.equals(currency)) {
102            amount = originalAmount;
103        } else {
104            throw new IllegalArgumentException("Currency conversion is not available");
105        }
106        
107        return amount;
108    }
109    
110    public TransactionGlEntry createTransactionGlEntry(final Transaction transaction, final Party groupParty, final TransactionGlAccountCategory transactionGlAccountCategory,
111            GlAccount glAccount, final Currency originalCurrency, final Long originalAmount, final BasePK createdBy) {
112        var accountingControl = Session.getModelController(AccountingControl.class);
113        
114        glAccount = getGlAccount(accountingControl, transactionGlAccountCategory, glAccount);
115        
116        Long amount = getAmount(glAccount, originalCurrency, originalAmount);
117        
118        return accountingControl.createTransactionGlEntry(transaction, getTransactionGlEntrySequence(accountingControl, transaction), null, groupParty, transactionGlAccountCategory, glAccount,
119                originalCurrency, originalAmount, amount, createdBy);
120    }
121    
122    public TransactionEntityRole createTransactionEntityRoleUsingNames(final Transaction transaction, final String transactionEntityRoleTypeName, final BasePK pk,
123            final BasePK createdBy) {
124        var accountingControl = Session.getModelController(AccountingControl.class);
125        TransactionEntityRoleType transactionEntityRoleType = accountingControl.getTransactionEntityRoleTypeByName(transaction.getLastDetail().getTransactionType(),
126                transactionEntityRoleTypeName);
127        
128        return createTransactionEntityRole(transaction, transactionEntityRoleType, pk, createdBy);
129    }
130    
131    public TransactionEntityRole createTransactionEntityRole(final Transaction transaction, final TransactionEntityRoleType transactionEntityRoleType, final BasePK pk,
132            final BasePK createdBy) {
133        var accountingControl = Session.getModelController(AccountingControl.class);
134        var coreControl = Session.getModelController(CoreControl.class);
135        EntityInstance entityInstance = coreControl.getEntityInstanceByBasePK(pk);
136        
137        if(!transactionEntityRoleType.getLastDetail().getEntityType().equals(entityInstance.getEntityType())) {
138            throw new IllegalArgumentException("entityInstance is not of the required EntityType");
139        }
140        
141        return accountingControl.createTransactionEntityRole(transaction, transactionEntityRoleType, entityInstance, createdBy);
142    }
143    
144    public void finishTransaction(final Transaction transaction) {
145        var accountingControl = Session.getModelController(AccountingControl.class);
146        
147        accountingControl.removeTransactionStatusByTransaction(transaction);
148        
149        PostingLogic.getInstance().postTransaction(transaction);
150    }
151    
152    public void testTransaction(final Session session, final BasePK testedBy) {
153        var accountingControl = Session.getModelController(AccountingControl.class);
154        var partyControl = Session.getModelController(PartyControl.class);
155        Party companyParty = partyControl.getDefaultPartyCompany().getParty();
156        Party divisionParty = partyControl.getDefaultPartyDivision(companyParty).getParty();
157        Party departmentParty = partyControl.getDefaultPartyDepartment(divisionParty).getParty();
158        Currency originalCurrency = accountingControl.getDefaultCurrency();
159        
160        Transaction transaction = createTransactionUsingNames(session, departmentParty, "TEST", null, testedBy);
161        createTransactionGlEntryUsingNames(transaction, null, "TEST_ACCOUNT_A", null, originalCurrency, 1999L, testedBy);
162        createTransactionGlEntryUsingNames(transaction, null, "TEST_ACCOUNT_B", null, originalCurrency, -1999L, testedBy);
163        createTransactionEntityRoleUsingNames(transaction, "TEST_ENTITY_INSTANCE_ROLE_TYPE", testedBy, testedBy);
164        finishTransaction(transaction);
165    }
166
167}