001 /*
002 * Copyright 2011 The Kuali Foundation.
003 *
004 * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
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 package org.kuali.kfs.module.endow.document.service.impl;
017
018 import java.math.BigDecimal;
019 import java.util.List;
020
021 import org.kuali.kfs.module.endow.businessobject.EndowmentSourceTransactionLine;
022 import org.kuali.kfs.module.endow.businessobject.EndowmentTransactionLine;
023 import org.kuali.kfs.module.endow.businessobject.EndowmentTransactionSecurity;
024 import org.kuali.kfs.module.endow.businessobject.EndowmentTransactionTaxLotLine;
025 import org.kuali.kfs.module.endow.businessobject.HoldingTaxLot;
026 import org.kuali.kfs.module.endow.businessobject.Security;
027 import org.kuali.kfs.module.endow.document.CorporateReorganizationDocument;
028 import org.kuali.kfs.module.endow.document.SecurityTransferDocument;
029 import org.kuali.kfs.module.endow.document.service.HoldingTaxLotService;
030 import org.kuali.kfs.module.endow.document.service.KEMService;
031 import org.kuali.kfs.module.endow.document.service.SecurityService;
032 import org.kuali.kfs.module.endow.document.service.UpdateSecurityTransferTargetTaxLotsService;
033 import org.kuali.kfs.module.endow.util.KEMCalculationRoundingHelper;
034 import org.kuali.rice.kns.util.KualiDecimal;
035 import org.kuali.rice.kns.util.ObjectUtils;
036
037 public class UpdateSecurityTransferTargetTaxLotsServiceImpl implements UpdateSecurityTransferTargetTaxLotsService {
038
039 private HoldingTaxLotService taxLotService;
040 private SecurityService securityService;
041 private KEMService kemService;
042
043 public void updateTransactionLineTaxLots(CorporateReorganizationDocument document, EndowmentTransactionLine transLine) {
044 // calculate the transaction line amount
045
046 //if there are no source transaction lines, do not process anything.
047 if (document.getSourceTransactionLines().size() > 0) {
048 // get the source transaction line and compute the unit value by dividing the source amount by the source number of units
049 EndowmentSourceTransactionLine sourceTransactionLine = (EndowmentSourceTransactionLine) document.getSourceTransactionLines().get(0);
050 EndowmentTransactionSecurity endowmentTransactionSecurity = document.getSourceTransactionSecurity();
051
052 if (ObjectUtils.isNotNull(sourceTransactionLine)) {
053 BigDecimal sourceAmount = BigDecimal.ZERO;
054 if (sourceTransactionLine.getTransactionAmount() != null) {
055 sourceAmount = sourceTransactionLine.getTransactionAmount().bigDecimalValue();
056 }
057 BigDecimal sourceUnits = BigDecimal.ZERO;
058 if (sourceTransactionLine.getTransactionUnits() != null) {
059 sourceUnits = sourceTransactionLine.getTransactionUnits().bigDecimalValue();
060 }
061
062 BigDecimal unitValue = BigDecimal.ZERO;
063 if (sourceUnits != null && sourceUnits.compareTo(BigDecimal.ZERO) != 0) {
064 unitValue = KEMCalculationRoundingHelper.divide(sourceAmount, sourceUnits, 5);
065 }
066
067 BigDecimal targetAmount = KEMCalculationRoundingHelper.multiply(transLine.getTransactionUnits().bigDecimalValue(), unitValue, 2);
068 transLine.setTransactionAmount(new KualiDecimal(sourceAmount));
069
070 EndowmentTransactionTaxLotLine taxLotLine = null;
071 boolean newLine = false;
072
073 if (transLine.getTaxLotLines() != null && transLine.getTaxLotLines().size() > 0) {
074 // there is only one tax lot line per each transaction line
075 taxLotLine = transLine.getTaxLotLines().get(0);
076 }
077 else {
078 // create and set a new tax lot line
079 newLine = true;
080 taxLotLine = new EndowmentTransactionTaxLotLine();
081 taxLotLine.setDocumentNumber(document.getDocumentNumber());
082 taxLotLine.setDocumentLineNumber(transLine.getTransactionLineNumber());
083 }
084
085 Security security = endowmentTransactionSecurity.getSecurity();
086 String securityId = endowmentTransactionSecurity.getSecurityID();
087 String regCode = endowmentTransactionSecurity.getRegistrationCode();
088 String ipIndicator = transLine.getTransactionIPIndicatorCode();
089 String kemid = transLine.getKemid();
090
091 // Step 6.
092 if (!security.getClassCode().isTaxLotIndicator()) {
093 taxLotLine.setTransactionHoldingLotNumber(1);
094 HoldingTaxLot taxLot = taxLotService.getByPrimaryKey(kemid, securityId, regCode, 1, ipIndicator);
095 if (taxLot != null) {
096 if (taxLot.getUnits().compareTo(BigDecimal.ZERO) == 0 && taxLot.getCost().compareTo(BigDecimal.ZERO) == 0) {
097 taxLotLine.setLotAcquiredDate(kemService.getCurrentProcessDate());
098 }
099 else {
100 taxLotLine.setLotAcquiredDate(taxLot.getAcquiredDate());
101 }
102 }
103 else {
104 taxLotLine.setLotAcquiredDate(kemService.getCurrentProcessDate());
105 }
106 // Step 7.
107 }
108 else {
109 List<HoldingTaxLot> taxLots = taxLotService.getAllTaxLots(kemid, securityId, regCode, ipIndicator);
110 int lotNumber = 1;
111 for (HoldingTaxLot taxLot : taxLots) {
112 if (lotNumber < taxLot.getLotNumber().intValue()) {
113 lotNumber = taxLot.getLotNumber().intValue();
114 }
115 }
116 taxLotLine.setTransactionHoldingLotNumber(Integer.valueOf(lotNumber));
117 taxLotLine.setLotAcquiredDate(kemService.getCurrentProcessDate());
118 }
119
120 taxLotLine.setLotUnits(transLine.getTransactionUnits().bigDecimalValue());
121 taxLotLine.setLotHoldingCost(sourceAmount);
122 taxLotLine.setKemid(kemid);
123 taxLotLine.setSecurityID(securityId);
124 taxLotLine.setRegistrationCode(regCode);
125 taxLotLine.setIpIndicator(ipIndicator);
126
127 // set the tax lot acquired date
128 setTaxLotAcquiredDate(taxLotLine, document, transLine);
129
130 // set the new tax lot indicator
131 setNewLotIndicator(taxLotLine, document);
132
133 if (newLine) {
134 transLine.getTaxLotLines().add(taxLotLine);
135 }
136 }
137 }
138 }
139
140 /**
141 * @see org.kuali.kfs.module.endow.document.service.UpdateSecurityTransferTargetTaxLotsService#updateTransactionLineTaxLots(org.kuali.kfs.module.endow.document.SecurityTransferDocument,
142 * org.kuali.kfs.module.endow.businessobject.EndowmentTransactionLine)
143 */
144 public void updateTransactionLineTaxLots(SecurityTransferDocument document, EndowmentTransactionLine transLine) {
145 // calculate the transaction line amount
146
147 //if there are no source transaction lines, do not process anything.
148 if (document.getSourceTransactionLines().size() > 0) {
149 // get the source transaction line and compute the unit value by dividing the source amount by the source number of units
150 EndowmentSourceTransactionLine sourceTransactionLine = (EndowmentSourceTransactionLine) document.getSourceTransactionLines().get(0);
151 EndowmentTransactionSecurity endowmentTransactionSecurity = document.getSourceTransactionSecurity();
152
153 if (ObjectUtils.isNotNull(sourceTransactionLine)) {
154 BigDecimal sourceAmount = BigDecimal.ZERO;
155 if (sourceTransactionLine.getTransactionAmount() != null) {
156 sourceAmount = sourceTransactionLine.getTransactionAmount().bigDecimalValue();
157 }
158 BigDecimal sourceUnits = BigDecimal.ZERO;
159 if (sourceTransactionLine.getTransactionUnits() != null) {
160 sourceUnits = sourceTransactionLine.getTransactionUnits().bigDecimalValue();
161 }
162
163 BigDecimal unitValue = BigDecimal.ZERO;
164 if (sourceUnits != null && sourceUnits.compareTo(BigDecimal.ZERO) != 0) {
165 unitValue = KEMCalculationRoundingHelper.divide(sourceAmount, sourceUnits, 5);
166 }
167
168 BigDecimal targetAmount = KEMCalculationRoundingHelper.multiply(transLine.getTransactionUnits().bigDecimalValue(), unitValue, 2);
169 // set transaction line target amount
170 transLine.setTransactionAmount(new KualiDecimal(targetAmount));
171
172 EndowmentTransactionTaxLotLine taxLotLine = null;
173 boolean newLine = false;
174
175 if (transLine.getTaxLotLines() != null && transLine.getTaxLotLines().size() > 0) {
176 // there is only one tax lot line per each transaction line
177 taxLotLine = transLine.getTaxLotLines().get(0);
178 }
179 else {
180 // create and set a new tax lot line
181 newLine = true;
182 taxLotLine = new EndowmentTransactionTaxLotLine();
183 taxLotLine.setDocumentNumber(document.getDocumentNumber());
184 taxLotLine.setDocumentLineNumber(transLine.getTransactionLineNumber());
185 taxLotLine.setTransactionHoldingLotNumber(1);
186 }
187
188 taxLotLine.setKemid(transLine.getKemid());
189 taxLotLine.setSecurityID(endowmentTransactionSecurity.getSecurityID());
190 taxLotLine.setRegistrationCode(endowmentTransactionSecurity.getRegistrationCode());
191 taxLotLine.setIpIndicator(transLine.getTransactionIPIndicatorCode());
192 taxLotLine.setLotUnits(transLine.getTransactionUnits().bigDecimalValue());
193 taxLotLine.setLotHoldingCost(targetAmount);
194
195 // set the tax lot acquired date
196 setTaxLotAcquiredDate(taxLotLine, document, transLine);
197
198 // set the new tax lot indicator
199 setNewLotIndicator(taxLotLine, document);
200
201 if (newLine) {
202 transLine.getTaxLotLines().add(taxLotLine);
203 }
204
205 }
206 }
207
208 }
209
210 /**
211 * Sets the Acquired date for the given tax lot line. If the tax lot indicator for the security (END_TRAN_SEC_T:
212 * SEC_TAX_LOT_IND) is No then for the lot acquired date - LOT_AQ_DATE - Search the END_HLDG_TAX_LOT_T records by KEMID by
213 * SEC_ID by REGIS_CD by HLDG_IP_IND [where HLDG_IP_IND is equal to END_TRAN_LN_T: TRAN_IP_IND_CD] by HLDG_LOT_NBR where
214 * HLDG_LOT_NBR is equal to 1 and return the HLDG_ACQD_DT: - If a lot exists for the security in END_HLDG_TAX_LOT_T, but the
215 * HLDG_UNITS and HLDG_COST are zero, insert the current date (System or Process) in LOT_ACQD_DT. - IF no lot exists for the
216 * security, then insert the current date (System or Process) in LOT_ACQD_DT. If the tax lot indicator for the security
217 * (END_TRAN_SEC_T: SEC_TAX_LOT_IND) is Yes: - LOT_AQ_DATE - insert the current date (System or Process) in this field
218 *
219 * @param taxLotLine the tax lot line for which to set the acquired date
220 * @param aiDocument the Asset Increase Document the tax lot line belongs to
221 * @param transLine the transaction line the tax lot is related to
222 */
223 private void setTaxLotAcquiredDate(EndowmentTransactionTaxLotLine taxLotLine, SecurityTransferDocument document, EndowmentTransactionLine transLine) {
224 EndowmentTransactionSecurity endowmentTransactionSecurity = document.getSourceTransactionSecurity();
225
226 Security security = securityService.getByPrimaryKey(endowmentTransactionSecurity.getSecurityID());
227
228 // if security tax lot indicator is 'No' and a tax lot exists for the kemid, security, registration code and income
229 // principal indicator - set the lot acquired date to be the tax lot holding acquired date if units and cost is not zero;
230 // otherwise set the date to be the current date
231 if (ObjectUtils.isNotNull(security) && !security.getClassCode().isTaxLotIndicator()) {
232 HoldingTaxLot holdingTaxLot = taxLotService.getByPrimaryKey(transLine.getKemid(), endowmentTransactionSecurity.getSecurityID(), endowmentTransactionSecurity.getRegistrationCode(), 1, transLine.getTransactionIPIndicatorCode());
233 if (ObjectUtils.isNotNull(holdingTaxLot)) {
234 if (holdingTaxLot.getUnits().equals(KualiDecimal.ZERO) && holdingTaxLot.getCost().equals(KualiDecimal.ZERO)) {
235 taxLotLine.setLotAcquiredDate(kemService.getCurrentDate());
236 }
237 else {
238 taxLotLine.setLotAcquiredDate(holdingTaxLot.getAcquiredDate());
239 }
240 }
241 else {
242 taxLotLine.setLotAcquiredDate(kemService.getCurrentDate());
243 }
244
245 }
246 // if security tax lot indicator is 'Yes' set the lot acquired date to be the current date
247 else {
248 taxLotLine.setLotAcquiredDate(kemService.getCurrentDate());
249 }
250 }
251
252 /**
253 * Sets the new lot indicator for the tax lot: -- if the security tax lot indicator is No then I think we should set the field
254 * to 'N'. When the batch process runs we might need to create a new entry on the holding tax lot table in case no entry is
255 * found for the given KEMID, security ID, registration code, holding ip indicator, and holding lot number = 1. In case there is
256 * an entry we will just update that one; -- if the security tax lot is Yes then the field should be set to 'Y'.We are always
257 * creating a new field with the lot number being the next sequential lot number.
258 *
259 * @param taxLotLine
260 * @param document
261 */
262 private void setNewLotIndicator(EndowmentTransactionTaxLotLine taxLotLine, SecurityTransferDocument document) {
263 EndowmentTransactionSecurity endowmentTransactionSecurity = document.getSourceTransactionSecurity();
264 Security security = securityService.getByPrimaryKey(endowmentTransactionSecurity.getSecurityID());
265
266 if (ObjectUtils.isNotNull(security)) {
267 // if the security tax lot indicator is No then I think we should set the field to 'N'. When the batch process runs we
268 // might need to create a new entry on the holding tax lot table in case no entry is found for the given KEMID, security
269 // ID, registration code, holding ip indicator, and holding lot number = 1. In case there is an entry we will just
270 // update that one
271 if (!security.getClassCode().isTaxLotIndicator()) {
272
273 taxLotLine.setNewLotIndicator(false);
274 }
275 // if the security tax lot is Yes then the field should be set to 'Y'.We are always creating a new field with the lot
276 // number being the next sequential lot number.
277 else {
278 taxLotLine.setNewLotIndicator(true);
279 }
280 }
281 }
282
283 private void setTaxLotAcquiredDate(EndowmentTransactionTaxLotLine taxLotLine, CorporateReorganizationDocument document, EndowmentTransactionLine transLine) {
284 EndowmentTransactionSecurity endowmentTransactionSecurity = document.getSourceTransactionSecurity();
285
286 Security security = securityService.getByPrimaryKey(endowmentTransactionSecurity.getSecurityID());
287
288 // if security tax lot indicator is 'No' and a tax lot exists for the kemid, security, registration code and income
289 // principal indicator - set the lot acquired date to be the tax lot holding acquired date if units and cost is not zero;
290 // otherwise set the date to be the current date
291 if (ObjectUtils.isNotNull(security) && !security.getClassCode().isTaxLotIndicator()) {
292 HoldingTaxLot holdingTaxLot = taxLotService.getByPrimaryKey(transLine.getKemid(), endowmentTransactionSecurity.getSecurityID(), endowmentTransactionSecurity.getRegistrationCode(), 1, transLine.getTransactionIPIndicatorCode());
293 if (ObjectUtils.isNotNull(holdingTaxLot)) {
294 if (holdingTaxLot.getUnits().equals(KualiDecimal.ZERO) && holdingTaxLot.getCost().equals(KualiDecimal.ZERO)) {
295 taxLotLine.setLotAcquiredDate(kemService.getCurrentDate());
296 }
297 else {
298 taxLotLine.setLotAcquiredDate(holdingTaxLot.getAcquiredDate());
299 }
300 }
301 else {
302 taxLotLine.setLotAcquiredDate(kemService.getCurrentDate());
303 }
304
305 }
306 // if security tax lot indicator is 'Yes' set the lot acquired date to be the current date
307 else {
308 taxLotLine.setLotAcquiredDate(kemService.getCurrentDate());
309 }
310 }
311
312 private void setNewLotIndicator(EndowmentTransactionTaxLotLine taxLotLine, CorporateReorganizationDocument document) {
313 EndowmentTransactionSecurity endowmentTransactionSecurity = document.getSourceTransactionSecurity();
314 Security security = securityService.getByPrimaryKey(endowmentTransactionSecurity.getSecurityID());
315
316 if (ObjectUtils.isNotNull(security)) {
317 // if the security tax lot indicator is No then I think we should set the field to 'N'. When the batch process runs we
318 // might need to create a new entry on the holding tax lot table in case no entry is found for the given KEMID, security
319 // ID, registration code, holding ip indicator, and holding lot number = 1. In case there is an entry we will just
320 // update that one
321 if (!security.getClassCode().isTaxLotIndicator()) {
322
323 taxLotLine.setNewLotIndicator(false);
324 }
325 // if the security tax lot is Yes then the field should be set to 'Y'.We are always creating a new field with the lot
326 // number being the next sequential lot number.
327 else {
328 taxLotLine.setNewLotIndicator(true);
329 }
330 }
331 }
332
333 /**
334 * Gets the taxLotService.
335 *
336 * @return taxLotService
337 */
338 protected HoldingTaxLotService getTaxLotService() {
339 return taxLotService;
340 }
341
342 /**
343 * Sets the taxLotService.
344 *
345 * @param taxLotService
346 */
347 public void setTaxLotService(HoldingTaxLotService taxLotService) {
348 this.taxLotService = taxLotService;
349 }
350
351 /**
352 * Gets the securityService.
353 *
354 * @return securityService
355 */
356 protected SecurityService getSecurityService() {
357 return securityService;
358 }
359
360 /**
361 * Sets the securityService.
362 *
363 * @param securityService
364 */
365 public void setSecurityService(SecurityService securityService) {
366 this.securityService = securityService;
367 }
368
369 /**
370 * Gets the kemService.
371 *
372 * @return kemService
373 */
374 protected KEMService getKemService() {
375 return kemService;
376 }
377
378 /**
379 * Sets the kemService.
380 *
381 * @param kemService
382 */
383 public void setKemService(KEMService kemService) {
384 this.kemService = kemService;
385 }
386 }