001: /*******************************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: *******************************************************************************/package org.ofbiz.accounting.util;
019:
020: import org.ofbiz.accounting.AccountingException;
021: import org.ofbiz.base.util.Debug;
022: import org.ofbiz.base.util.UtilMisc;
023: import org.ofbiz.entity.GenericDelegator;
024: import org.ofbiz.entity.GenericEntityException;
025: import org.ofbiz.entity.GenericValue;
026:
027: public class UtilAccounting {
028:
029: public static String module = UtilAccounting.class.getName();
030:
031: /**
032: * Get the GL Account for a product or the default account type based on input. This replaces the simple-method service
033: * getProductOrgGlAccount. First it will look in ProductGlAccount using the primary keys productId and
034: * productGlAccountTypeId. If none is found, it will look up GlAccountTypeDefault to find the default account for
035: * organizationPartyId with type glAccountTypeId.
036: *
037: * @param productId When searching for ProductGlAccounts, specify the productId
038: * @param glAccountTypeId The default glAccountTypeId to look for if no ProductGlAccount is found
039: * @param organizationPartyId The organization party of the default account
040: * @return The account ID (glAccountId) found
041: * @throws AccountingException When the no accounts found or an entity exception occurs
042: */
043: public static String getProductOrgGlAccountId(String productId,
044: String glAccountTypeId, String organizationPartyId,
045: GenericDelegator delegator) throws AccountingException {
046:
047: GenericValue account = null;
048: try {
049: // first try to find the account in ProductGlAccount
050: account = delegator.findByPrimaryKeyCache(
051: "ProductGlAccount", UtilMisc.toMap("productId",
052: productId, "glAccountTypeId",
053: glAccountTypeId, "organizationPartyId",
054: organizationPartyId));
055: } catch (GenericEntityException e) {
056: throw new AccountingException(
057: "Failed to find a ProductGLAccount for productId ["
058: + productId + "], organization ["
059: + organizationPartyId
060: + "], and productGlAccountTypeId ["
061: + glAccountTypeId + "].", e);
062: }
063:
064: // otherwise try the default accounts
065: if (account == null) {
066: try {
067: account = delegator.findByPrimaryKeyCache(
068: "GlAccountTypeDefault", UtilMisc.toMap(
069: "glAccountTypeId", glAccountTypeId,
070: "organizationPartyId",
071: organizationPartyId));
072: } catch (GenericEntityException e) {
073: throw new AccountingException(
074: "Failed to find a GlAccountTypeDefault for glAccountTypeId ["
075: + glAccountTypeId
076: + "] and organizationPartyId ["
077: + organizationPartyId + "].", e);
078: }
079: }
080:
081: // if no results yet, serious problem
082: if (account == null) {
083: throw new AccountingException(
084: "Failed to find any accounts for productId ["
085: + productId
086: + "], organization ["
087: + organizationPartyId
088: + "], and productGlAccountTypeId ["
089: + glAccountTypeId
090: + "] or any accounts in GlAccountTypeDefault for glAccountTypeId ["
091: + glAccountTypeId
092: + "] and organizationPartyId ["
093: + organizationPartyId
094: + "]. Please check your data to make sure that at least a GlAccountTypeDefault is defined for this account type and organization.");
095: }
096:
097: // otherwise return the glAccountId
098: return account.getString("glAccountId");
099: }
100:
101: /**
102: * As above, but explicitly looking for default account for given type and organization
103: *
104: * @param glAccountTypeId The type of account
105: * @param organizationPartyId The organization of the account
106: * @return The default account ID (glAccountId) for this type
107: * @throws AccountingException When the default is not configured
108: */
109: public static String getDefaultAccountId(String glAccountTypeId,
110: String organizationPartyId, GenericDelegator delegator)
111: throws AccountingException {
112: return getProductOrgGlAccountId(null, glAccountTypeId,
113: organizationPartyId, delegator);
114: }
115:
116: /**
117: * Little method to figure out the net or ending balance of a GlAccountHistory or GlAccountAndHistory value, based on what kind
118: * of account (DEBIT or CREDIT) it is
119: * @param account - GlAccountHistory or GlAccountAndHistory value
120: * @return balance - a Double
121: */
122: public static Double getNetBalance(GenericValue account,
123: String debugModule) {
124: try {
125: GenericValue glAccount = account.getRelatedOne("GlAccount");
126: double balance = 0.0;
127: if (isDebitAccount(glAccount)) {
128: balance = account.getDouble("postedDebits")
129: .doubleValue()
130: - account.getDouble("postedCredits")
131: .doubleValue();
132: } else if (isCreditAccount(glAccount)) {
133: balance = account.getDouble("postedCredits")
134: .doubleValue()
135: - account.getDouble("postedDebits")
136: .doubleValue();
137: }
138: return new Double(balance);
139: } catch (GenericEntityException ex) {
140: Debug.logError(ex.getMessage(), debugModule);
141: return null;
142: }
143: }
144:
145: /**
146: * Recurses up payment type tree via parentTypeId to see if input payment type ID is in tree.
147: */
148: private static boolean isPaymentTypeRecurse(
149: GenericValue paymentType, String inputTypeId)
150: throws GenericEntityException {
151:
152: // first check the parentTypeId against inputTypeId
153: String parentTypeId = paymentType.getString("parentTypeId");
154: if (parentTypeId == null) {
155: return false;
156: }
157: if (parentTypeId.equals(inputTypeId)) {
158: return true;
159: }
160:
161: // otherwise, we have to go to the grandparent (recurse)
162: return isPaymentTypeRecurse(paymentType
163: .getRelatedOne("ParentPaymentType"), inputTypeId);
164: }
165:
166: /**
167: * Checks if a payment is of a specified PaymentType.paymentTypeId. Return false if payment is null. It's better to use the
168: * more specific calls like isTaxPayment().
169: */
170: public static boolean isPaymentType(GenericValue payment,
171: String inputTypeId) throws GenericEntityException {
172: if (payment == null) {
173: return false;
174: }
175:
176: GenericValue paymentType = payment
177: .getRelatedOneCache("PaymentType");
178: if (paymentType == null) {
179: throw new GenericEntityException(
180: "Cannot find PaymentType for paymentId "
181: + payment.getString("paymentId"));
182: }
183:
184: String paymentTypeId = paymentType.getString("paymentTypeId");
185: if (inputTypeId.equals(paymentTypeId)) {
186: return true;
187: }
188:
189: // recurse up tree
190: return isPaymentTypeRecurse(paymentType, inputTypeId);
191: }
192:
193: public static boolean isTaxPayment(GenericValue payment)
194: throws GenericEntityException {
195: return isPaymentType(payment, "TAX_PAYMENT");
196: }
197:
198: public static boolean isDisbursement(GenericValue payment)
199: throws GenericEntityException {
200: return isPaymentType(payment, "DISBURSEMENT");
201: }
202:
203: public static boolean isReceipt(GenericValue payment)
204: throws GenericEntityException {
205: return isPaymentType(payment, "RECEIPT");
206: }
207:
208: /**
209: * Determines if a glAccountClass is of a child of a certain parent glAccountClass.
210: */
211: public static boolean isAccountClassClass(
212: GenericValue glAccountClass, String parentGlAccountClassId)
213: throws GenericEntityException {
214: if (glAccountClass == null)
215: return false;
216:
217: // check current class against input classId
218: if (parentGlAccountClassId.equals(glAccountClass
219: .get("glAccountClassId"))) {
220: return true;
221: }
222:
223: // check parentClassId against inputClassId
224: String parentClassId = glAccountClass
225: .getString("parentClassId");
226: if (parentClassId == null) {
227: return false;
228: }
229: if (parentClassId.equals(parentGlAccountClassId)) {
230: return true;
231: }
232:
233: // otherwise, we have to go to the grandparent (recurse)
234: return isAccountClassClass(glAccountClass
235: .getRelatedOneCache("ParentGlAccountClass"),
236: parentGlAccountClassId);
237: }
238:
239: /**
240: * Checks if a GL account is of a specified GlAccountClass.glAccountClassId. Returns false if account is null. It's better to use the
241: * more specific calls like isDebitAccount().
242: */
243: public static boolean isAccountClass(GenericValue glAccount,
244: String glAccountClassId) throws GenericEntityException {
245: if (glAccount == null) {
246: return false;
247: }
248:
249: GenericValue glAccountClass = glAccount
250: .getRelatedOneCache("GlAccountClass");
251: if (glAccountClass == null) {
252: throw new GenericEntityException(
253: "Cannot find GlAccountClass for glAccountId "
254: + glAccount.getString("glAccountId"));
255: }
256:
257: return isAccountClassClass(glAccountClass, glAccountClassId);
258: }
259:
260: public static boolean isDebitAccount(GenericValue account)
261: throws GenericEntityException {
262: return isAccountClass(account, "DEBIT");
263: }
264:
265: public static boolean isCreditAccount(GenericValue account)
266: throws GenericEntityException {
267: return isAccountClass(account, "CREDIT");
268: }
269:
270: public static boolean isAssetAccount(GenericValue account)
271: throws GenericEntityException {
272: return isAccountClass(account, "ASSET");
273: }
274:
275: public static boolean isLiabilityAccount(GenericValue account)
276: throws GenericEntityException {
277: return isAccountClass(account, "LIABILITY");
278: }
279:
280: public static boolean isEquityAccount(GenericValue account)
281: throws GenericEntityException {
282: return isAccountClass(account, "EQUITY");
283: }
284:
285: public static boolean isIncomeAccount(GenericValue account)
286: throws GenericEntityException {
287: return isAccountClass(account, "INCOME");
288: }
289:
290: public static boolean isRevenueAccount(GenericValue account)
291: throws GenericEntityException {
292: return isAccountClass(account, "REVENUE");
293: }
294:
295: public static boolean isExpenseAccount(GenericValue account)
296: throws GenericEntityException {
297: return isAccountClass(account, "EXPENSE");
298: }
299: }
|