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
017 package org.kuali.kfs.gl.businessobject;
018
019 import java.sql.Date;
020 import java.util.LinkedHashMap;
021 import java.util.Map;
022
023 import org.apache.commons.lang.StringUtils;
024 import org.kuali.kfs.coa.businessobject.Account;
025 import org.kuali.kfs.coa.businessobject.BalanceType;
026 import org.kuali.kfs.coa.businessobject.Chart;
027 import org.kuali.kfs.coa.businessobject.ObjectCode;
028 import org.kuali.kfs.coa.businessobject.ObjectType;
029 import org.kuali.kfs.coa.service.AccountService;
030 import org.kuali.kfs.gl.GeneralLedgerConstants;
031 import org.kuali.kfs.sys.KFSConstants;
032 import org.kuali.kfs.sys.KFSKeyConstants;
033 import org.kuali.kfs.sys.KFSPropertyConstants;
034 import org.kuali.kfs.sys.businessobject.UniversityDate;
035 import org.kuali.kfs.sys.context.SpringContext;
036 import org.kuali.rice.kns.bo.PersistableBusinessObjectBase;
037 import org.kuali.rice.kns.util.KualiDecimal;
038 import org.kuali.rice.kns.util.MessageMap;
039
040 /**
041 * CollectorDetail Business Object.
042 */
043 public class CollectorDetail extends PersistableBusinessObjectBase {
044
045 private String universityFiscalPeriodCode;
046 private Integer universityFiscalYear;
047 private Date createDate;
048 private Integer transactionLedgerEntrySequenceNumber;
049 private String chartOfAccountsCode;
050 private String accountNumber;
051 private String subAccountNumber;
052 private String financialObjectCode;
053 private String financialSubObjectCode;
054 private String financialBalanceTypeCode;
055 private String financialObjectTypeCode;
056 private String collectorDetailSequenceNumber;
057 private String financialDocumentTypeCode;
058 private String financialSystemOriginationCode;
059 private String documentNumber;
060 private KualiDecimal collectorDetailItemAmount;
061 private String collectorDetailNoteText;
062 private String glCreditCode;
063
064 private ObjectCode financialObject;
065 private Account account;
066 private Chart chartOfAccounts;
067 private ObjectType objectType;
068 private BalanceType balanceType;
069
070 private static CollectorDetailFieldUtil collectorDetailFieldUtil;
071
072 /**
073 * Default constructor.
074 */
075 public CollectorDetail() {
076 setSubAccountNumber(KFSConstants.getDashSubAccountNumber());
077 setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode());
078 }
079
080 /**
081 * Gets the universityFiscalPeriodCode attribute.
082 *
083 * @return Returns the universityFiscalPeriodCode
084 */
085 public String getUniversityFiscalPeriodCode() {
086 return universityFiscalPeriodCode;
087 }
088
089 /**
090 * Sets the universityFiscalPeriodCode attribute.
091 *
092 * @param universityFiscalPeriodCode The universityFiscalPeriodCode to set.
093 */
094 public void setUniversityFiscalPeriodCode(String universityFiscalPeriodCode) {
095 this.universityFiscalPeriodCode = universityFiscalPeriodCode;
096 }
097
098
099 /**
100 * Gets the universityFiscalYear attribute.
101 *
102 * @return Returns the universityFiscalYear
103 */
104 public Integer getUniversityFiscalYear() {
105 return universityFiscalYear;
106 }
107
108 /**
109 * Sets the universityFiscalYear attribute.
110 *
111 * @param universityFiscalYear The universityFiscalYear to set.
112 */
113 public void setUniversityFiscalYear(Integer universityFiscalYear) {
114 this.universityFiscalYear = universityFiscalYear;
115 }
116
117
118 /**
119 * Gets the createDate attribute.
120 *
121 * @return Returns the createDate
122 */
123 public Date getCreateDate() {
124 return createDate;
125 }
126
127 /**
128 * Sets the createDate attribute.
129 *
130 * @param createDate The createDate to set.
131 */
132 public void setCreateDate(Date createDate) {
133 this.createDate = createDate;
134 }
135
136 /**
137 * Gets the transactionLedgerEntrySequenceNumber attribute.
138 * @return Returns the transactionLedgerEntrySequenceNumber.
139 */
140 public Integer getTransactionLedgerEntrySequenceNumber() {
141 return transactionLedgerEntrySequenceNumber;
142 }
143
144 /**
145 * Sets the transactionLedgerEntrySequenceNumber attribute value.
146 * @param transactionLedgerEntrySequenceNumber The transactionLedgerEntrySequenceNumber to set.
147 */
148 public void setTransactionLedgerEntrySequenceNumber(Integer transactionLedgerEntrySequenceNumber) {
149 this.transactionLedgerEntrySequenceNumber = transactionLedgerEntrySequenceNumber;
150 }
151
152 /**
153 * Gets the chartOfAccountsCode attribute.
154 *
155 * @return Returns the chartOfAccountsCode
156 */
157 public String getChartOfAccountsCode() {
158 return chartOfAccountsCode;
159 }
160
161 /**
162 * Sets the chartOfAccountsCode attribute.
163 *
164 * @param chartOfAccountsCode The chartOfAccountsCode to set.
165 */
166 public void setChartOfAccountsCode(String chartOfAccountsCode) {
167 this.chartOfAccountsCode = chartOfAccountsCode;
168 }
169
170
171 /**
172 * Gets the accountNumber attribute.
173 *
174 * @return Returns the accountNumber
175 */
176 public String getAccountNumber() {
177 return accountNumber;
178 }
179
180 /**
181 * Sets the accountNumber attribute.
182 *
183 * @param accountNumber The accountNumber to set.
184 */
185 public void setAccountNumber(String accountNumber) {
186 this.accountNumber = accountNumber;
187 }
188
189
190 /**
191 * Gets the subAccountNumber attribute.
192 *
193 * @return Returns the subAccountNumber
194 */
195 public String getSubAccountNumber() {
196 return subAccountNumber;
197 }
198
199 /**
200 * Sets the subAccountNumber attribute.
201 *
202 * @param subAccountNumber The subAccountNumber to set.
203 */
204 public void setSubAccountNumber(String subAccountNumber) {
205 this.subAccountNumber = subAccountNumber;
206 }
207
208
209 /**
210 * Gets the financialObjectCode attribute.
211 *
212 * @return Returns the financialObjectCode
213 */
214 public String getFinancialObjectCode() {
215 return financialObjectCode;
216 }
217
218 /**
219 * Sets the financialObjectCode attribute.
220 *
221 * @param financialObjectCode The financialObjectCode to set.
222 */
223 public void setFinancialObjectCode(String financialObjectCode) {
224 this.financialObjectCode = financialObjectCode;
225 }
226
227
228 /**
229 * Gets the financialSubObjectCode attribute.
230 *
231 * @return Returns the financialSubObjectCode
232 */
233 public String getFinancialSubObjectCode() {
234 return financialSubObjectCode;
235 }
236
237 /**
238 * Sets the financialSubObjectCode attribute.
239 *
240 * @param financialSubObjectCode The financialSubObjectCode to set.
241 */
242 public void setFinancialSubObjectCode(String financialSubObjectCode) {
243 this.financialSubObjectCode = financialSubObjectCode;
244 }
245
246
247 /**
248 * Gets the collectorDetailSequenceNumber attribute.
249 *
250 * @return Returns the collectorDetailSequenceNumber
251 */
252 public String getCollectorDetailSequenceNumber() {
253 return collectorDetailSequenceNumber;
254 }
255
256 /**
257 * Sets the collectorDetailSequenceNumber attribute.
258 *
259 * @param collectorDetailSequenceNumber The collectorDetailSequenceNumber to set.
260 */
261 public void setCollectorDetailSequenceNumber(String collectorDetailSequenceNumber) {
262 this.collectorDetailSequenceNumber = collectorDetailSequenceNumber;
263 }
264
265
266 /**
267 * Gets the financialDocumentTypeCode attribute.
268 *
269 * @return Returns the financialDocumentTypeCode
270 */
271 public String getFinancialDocumentTypeCode() {
272 return financialDocumentTypeCode;
273 }
274
275 /**
276 * Sets the financialDocumentTypeCode attribute.
277 *
278 * @param financialDocumentTypeCode The financialDocumentTypeCode to set.
279 */
280 public void setFinancialDocumentTypeCode(String financialDocumentTypeCode) {
281 this.financialDocumentTypeCode = financialDocumentTypeCode;
282 }
283
284
285 /**
286 * Gets the financialSystemOriginationCode attribute.
287 *
288 * @return Returns the financialSystemOriginationCode
289 */
290 public String getFinancialSystemOriginationCode() {
291 return financialSystemOriginationCode;
292 }
293
294 /**
295 * Sets the financialSystemOriginationCode attribute.
296 *
297 * @param financialSystemOriginationCode The financialSystemOriginationCode to set.
298 */
299 public void setFinancialSystemOriginationCode(String financialSystemOriginationCode) {
300 this.financialSystemOriginationCode = financialSystemOriginationCode;
301 }
302
303
304 /**
305 * Gets the documentNumber attribute.
306 *
307 * @return Returns the documentNumber
308 */
309 public String getDocumentNumber() {
310 return documentNumber;
311 }
312
313 /**
314 * Sets the documentNumber attribute.
315 *
316 * @param documentNumber The documentNumber to set.
317 */
318 public void setDocumentNumber(String documentNumber) {
319 this.documentNumber = documentNumber;
320 }
321
322
323 /**
324 * Gets the collectorDetailItemAmount attribute.
325 *
326 * @return Returns the collectorDetailItemAmount
327 */
328 public KualiDecimal getCollectorDetailItemAmount() {
329 return collectorDetailItemAmount;
330 }
331
332 /**
333 * Sets the collectorDetailItemAmount attribute.
334 *
335 * @param collectorDetailItemAmount The collectorDetailItemAmount to set.
336 */
337 public void setCollectorDetailItemAmount(KualiDecimal collectorDetailItemAmount) {
338 this.collectorDetailItemAmount = collectorDetailItemAmount;
339 }
340
341 public void setCollectorDetailItemAmount(String collectorDetailItemAmount) {
342 this.collectorDetailItemAmount = new KualiDecimal(collectorDetailItemAmount);
343 }
344
345 public void clearcollectorDetailItemAmount() {
346 this.collectorDetailItemAmount = null;
347 }
348
349 /**
350 * Gets the collectorDetailNoteText attribute.
351 *
352 * @return Returns the collectorDetailNoteText
353 */
354 public String getCollectorDetailNoteText() {
355 return collectorDetailNoteText;
356 }
357
358 /**
359 * Sets the collectorDetailNoteText attribute.
360 *
361 * @param collectorDetailNoteText The collectorDetailNoteText to set.
362 */
363 public void setCollectorDetailNoteText(String collectorDetailNoteText) {
364 this.collectorDetailNoteText = collectorDetailNoteText;
365 }
366
367
368 /**
369 * Gets the financialObject attribute.
370 *
371 * @return Returns the financialObject
372 */
373 public ObjectCode getFinancialObject() {
374 return financialObject;
375 }
376
377 /**
378 * Sets the financialObject attribute.
379 *
380 * @param financialObject The financialObject to set.
381 * @deprecated
382 */
383 public void setFinancialObject(ObjectCode financialObject) {
384 this.financialObject = financialObject;
385 }
386
387 /**
388 * Gets the account attribute.
389 *
390 * @return Returns the account
391 */
392 public Account getAccount() {
393 return account;
394 }
395
396 /**
397 * Sets the account attribute.
398 *
399 * @param account The account to set.
400 * @deprecated
401 */
402 public void setAccount(Account account) {
403 this.account = account;
404 }
405
406 /**
407 * Gets the chartOfAccounts attribute.
408 *
409 * @return Returns the chartOfAccounts
410 */
411 public Chart getChartOfAccounts() {
412 return chartOfAccounts;
413 }
414
415 /**
416 * Sets the chartOfAccounts attribute.
417 *
418 * @param chartOfAccounts The chartOfAccounts to set.
419 * @deprecated
420 */
421 public void setChartOfAccounts(Chart chartOfAccounts) {
422 this.chartOfAccounts = chartOfAccounts;
423 }
424
425 /**
426 * @see org.kuali.rice.kns.bo.BusinessObjectBase#toStringMapper()
427 */
428 protected LinkedHashMap toStringMapper() {
429 LinkedHashMap m = new LinkedHashMap();
430 m.put("universityFiscalPeriodCode", getUniversityFiscalPeriodCode());
431 if (getUniversityFiscalYear() != null) {
432 m.put("universityFiscalYear", getUniversityFiscalYear().toString());
433 }
434 if (getCreateDate() != null) {
435 m.put("createDate", getCreateDate().toString());
436 }
437 m.put("transactionLedgerEntrySequenceNumber", getTransactionLedgerEntrySequenceNumber());
438 m.put("chartOfAccountsCode", getChartOfAccountsCode());
439 m.put("accountNumber", getAccountNumber());
440 m.put("subAccountNumber", getSubAccountNumber());
441 m.put("financialObjectCode", getFinancialObjectCode());
442 m.put("financialSubObjectCode", getFinancialSubObjectCode());
443 m.put("collectorDetailSequenceNumber", getCollectorDetailSequenceNumber());
444 m.put("financialDocumentTypeCode", getFinancialDocumentTypeCode());
445 m.put(KFSPropertyConstants.DOCUMENT_NUMBER, getDocumentNumber());
446 return m;
447 }
448
449 /**
450 * Gets the balanceTyp attribute.
451 *
452 * @return Returns the balanceTyp.
453 */
454 public BalanceType getBalanceType() {
455 return balanceType;
456 }
457
458 /**
459 * Sets the balanceTyp attribute value.
460 *
461 * @param balanceTyp The balanceTyp to set.
462 */
463 public void setBalanceType(BalanceType balanceTyp) {
464 this.balanceType = balanceTyp;
465 }
466
467 /**
468 * Gets the financialBalanceTypeCode attribute.
469 *
470 * @return Returns the financialBalanceTypeCode.
471 */
472 public String getFinancialBalanceTypeCode() {
473 return financialBalanceTypeCode;
474 }
475
476 /**
477 * Sets the financialBalanceTypeCode attribute value.
478 *
479 * @param financialBalanceTypeCode The financialBalanceTypeCode to set.
480 */
481 public void setFinancialBalanceTypeCode(String financialBalanceTypeCode) {
482 this.financialBalanceTypeCode = financialBalanceTypeCode;
483 }
484
485 /**
486 * Gets the financialObjectTypeCode attribute.
487 *
488 * @return Returns the financialObjectTypeCode.
489 */
490 public String getFinancialObjectTypeCode() {
491 return financialObjectTypeCode;
492 }
493
494 /**
495 * Sets the financialObjectTypeCode attribute value.
496 *
497 * @param financialObjectTypeCode The financialObjectTypeCode to set.
498 */
499 public void setFinancialObjectTypeCode(String financialObjectTypeCode) {
500 this.financialObjectTypeCode = financialObjectTypeCode;
501 }
502
503 /**
504 * Gets the glCreditCode attribute.
505 *
506 * @return Returns the glCreditCode.
507 */
508 public String getGlCreditCode() {
509 return glCreditCode;
510 }
511
512 /**
513 * Sets the glCreditCode attribute value.
514 *
515 * @param glCreditCode The glCreditCode to set.
516 */
517 public void setGLCreditCode(String glCreditCode) {
518 this.glCreditCode = glCreditCode;
519 }
520
521
522 /**
523 * Gets the objectType attribute.
524 *
525 * @return Returns the objectType.
526 */
527 public ObjectType getObjectType() {
528 return objectType;
529 }
530
531 /**
532 * Sets the objectType attribute value.
533 *
534 * @param objectType The objectType to set.
535 */
536 public void setObjectType(ObjectType objectType) {
537 this.objectType = objectType;
538 }
539
540 protected String getValue(String headerLine, int s, int e) {
541 return org.springframework.util.StringUtils.trimTrailingWhitespace(StringUtils.substring(headerLine, s, e));
542 }
543
544 /**
545 * @return the static instance of the CollectorBatchrFieldUtil
546 */
547 protected static CollectorDetailFieldUtil getCollectorDetailFieldUtil() {
548 if (collectorDetailFieldUtil == null) {
549 collectorDetailFieldUtil = new CollectorDetailFieldUtil();
550 }
551 return collectorDetailFieldUtil;
552 }
553
554 public void setFromFileForCollectorDetail(String detailLine, Date curDate, UniversityDate universityDate, int lineNumber, MessageMap messageMap) {
555
556 try{
557
558 final Map<String, Integer> pMap = getCollectorDetailFieldUtil().getFieldBeginningPositionMap();
559
560 detailLine = org.apache.commons.lang.StringUtils.rightPad(detailLine, GeneralLedgerConstants.getSpaceAllCollectorDetailFields().length(), ' ');
561
562 setCreateDate(curDate);
563 if (!GeneralLedgerConstants.getSpaceUniversityFiscalYear().equals(detailLine.substring(pMap.get(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR), pMap.get(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE)))) {
564 try {
565 setUniversityFiscalYear(new Integer(getValue(detailLine, pMap.get(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR), pMap.get(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE))));
566 }
567 catch (NumberFormatException e) {
568 messageMap.putError(KFSConstants.GLOBAL_ERRORS, KFSKeyConstants.ERROR_CUSTOM, "Collector detail university fiscal year " + lineNumber + " string " + detailLine.substring(pMap.get(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR), pMap.get(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE)));
569 setUniversityFiscalYear(null);
570 }
571 }
572 else {
573 setUniversityFiscalYear(null);
574 }
575
576 if (!GeneralLedgerConstants.getSpaceChartOfAccountsCode().equals(detailLine.substring(pMap.get(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR), pMap.get(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE))))
577 setChartOfAccountsCode(getValue(detailLine, pMap.get(KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE), pMap.get(KFSPropertyConstants.ACCOUNT_NUMBER)));
578 else
579 setChartOfAccountsCode(GeneralLedgerConstants.getSpaceChartOfAccountsCode());
580 setAccountNumber(getValue(detailLine, pMap.get(KFSPropertyConstants.ACCOUNT_NUMBER), pMap.get(KFSPropertyConstants.SUB_ACCOUNT_NUMBER)));
581
582 // if chart code is empty while accounts cannot cross charts, then derive chart code from account number
583 AccountService acctserv = SpringContext.getBean(AccountService.class);
584 if (StringUtils.isEmpty(getChartOfAccountsCode()) && StringUtils.isNotEmpty(getAccountNumber()) && !acctserv.accountsCanCrossCharts()) {
585 Account account = acctserv.getUniqueAccountForAccountNumber(getAccountNumber());
586 if (account != null) {
587 setChartOfAccountsCode(account.getChartOfAccountsCode());
588 }
589 }
590
591 setSubAccountNumber(getValue(detailLine, pMap.get(KFSPropertyConstants.SUB_ACCOUNT_NUMBER), pMap.get(KFSPropertyConstants.FINANCIAL_OBJECT_CODE)));
592 setFinancialObjectCode(getValue(detailLine, pMap.get(KFSPropertyConstants.FINANCIAL_OBJECT_CODE), pMap.get(KFSPropertyConstants.FINANCIAL_SUB_OBJECT_CODE)));
593 setFinancialSubObjectCode(getValue(detailLine, pMap.get(KFSPropertyConstants.FINANCIAL_SUB_OBJECT_CODE), pMap.get(KFSPropertyConstants.FINANCIAL_BALANCE_TYPE_CODE)));
594 // We are in Collector Detail for ID Billing Details because the value from file positions 25, 26 = DT. We don not want to set
595 // Financial Balance Type Code = DT. Sterling stated for now we can set it to "AC".
596 // setFinancialBalanceTypeCode(getValue(detailLine, pMap.get(KFSPropertyConstants.FINANCIAL_BALANCE_TYPE_CODE), pMap.get(KFSPropertyConstants.FINANCIAL_OBJECT_TYPE_CODE)));
597 setFinancialBalanceTypeCode(GeneralLedgerConstants.FINALNCIAL_BALANCE_TYPE_FOR_COLLECTOR_DETAIL_RECORD);
598 setFinancialObjectTypeCode(getValue(detailLine, pMap.get(KFSPropertyConstants.FINANCIAL_OBJECT_TYPE_CODE), pMap.get(KFSPropertyConstants.COLLECTOR_DETAIL_SEQUENCE_NUMBER)));
599 setUniversityFiscalPeriodCode(universityDate.getUniversityFiscalAccountingPeriod());
600 setCollectorDetailSequenceNumber(getValue(detailLine, pMap.get(KFSPropertyConstants.COLLECTOR_DETAIL_SEQUENCE_NUMBER), pMap.get(KFSPropertyConstants.FINANCIAL_DOCUMENT_TYPE_CODE)));
601 setFinancialDocumentTypeCode(getValue(detailLine, pMap.get(KFSPropertyConstants.FINANCIAL_DOCUMENT_TYPE_CODE), pMap.get(KFSPropertyConstants.FINANCIAL_SYSTEM_ORIGINATION_CODE)));
602 setFinancialSystemOriginationCode(getValue(detailLine, pMap.get(KFSPropertyConstants.FINANCIAL_SYSTEM_ORIGINATION_CODE), pMap.get(KFSPropertyConstants.DOCUMENT_NUMBER)));
603 setDocumentNumber(getValue(detailLine, pMap.get(KFSPropertyConstants.DOCUMENT_NUMBER), pMap.get(KFSPropertyConstants.COLLECTOR_DETAIL_AMOUNT)));
604 try {
605 setCollectorDetailItemAmount(getValue(detailLine, pMap.get(KFSPropertyConstants.COLLECTOR_DETAIL_AMOUNT), pMap.get(KFSPropertyConstants.COLLECTOR_DETAIL_GL_CREDIT_CODE)));
606 }
607 catch (NumberFormatException e) {
608 setCollectorDetailItemAmount(KualiDecimal.ZERO);
609 messageMap.putError(KFSConstants.GLOBAL_ERRORS, KFSKeyConstants.ERROR_CUSTOM, "Collector detail amount cannot be parsed on line " + lineNumber + " amount string " + detailLine.substring(pMap.get(KFSPropertyConstants.COLLECTOR_DETAIL_AMOUNT), pMap.get(KFSPropertyConstants.GL_CREDIT_CODE)));
610 }
611 if (KFSConstants.GL_CREDIT_CODE.equalsIgnoreCase(getValue(detailLine, pMap.get(KFSPropertyConstants.COLLECTOR_DETAIL_GL_CREDIT_CODE), pMap.get(KFSPropertyConstants.COLLECTOR_DETAIL_NOTE_TEXT)))) {
612 setCollectorDetailItemAmount(getCollectorDetailItemAmount().negated());
613 }
614 setCollectorDetailNoteText(getValue(detailLine, pMap.get(KFSPropertyConstants.COLLECTOR_DETAIL_NOTE_TEXT), GeneralLedgerConstants.getSpaceAllCollectorDetailFields().length()));
615
616 if (org.apache.commons.lang.StringUtils.isEmpty(getSubAccountNumber())) {
617 setSubAccountNumber(KFSConstants.getDashSubAccountNumber());
618 }
619 if (org.apache.commons.lang.StringUtils.isEmpty(getFinancialSubObjectCode())) {
620 setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode());
621 }
622 if (org.apache.commons.lang.StringUtils.isEmpty(getCollectorDetailSequenceNumber())) {
623 setCollectorDetailSequenceNumber(" ");
624 }
625 } catch (Exception e){
626 throw new RuntimeException(e + " occurred in CollectorDetail.setFromFileForCollectorDetail()");
627 }
628 }
629 }