View Javadoc
1   package org.kuali.ole.deliver.controller.checkout;
2   
3   import org.apache.commons.collections.CollectionUtils;
4   import org.apache.commons.lang3.StringUtils;
5   import org.apache.log4j.Logger;
6   import org.kuali.ole.OLEConstants;
7   import org.kuali.ole.deliver.bo.*;
8   import org.kuali.ole.deliver.drools.DroolsConstants;
9   import org.kuali.ole.deliver.form.CircForm;
10  import org.kuali.ole.deliver.util.ErrorMessage;
11  import org.kuali.ole.deliver.util.ItemInfoUtil;
12  import org.kuali.ole.deliver.util.NoticeInfo;
13  import org.kuali.ole.deliver.util.OleItemRecordForCirc;
14  import org.kuali.ole.docstore.engine.service.storage.rdbms.pojo.ItemRecord;
15  import org.kuali.ole.utility.OleStopWatch;
16  import org.kuali.rice.krad.util.GlobalVariables;
17  import org.kuali.rice.krad.web.form.UifFormBase;
18  
19  import java.sql.Timestamp;
20  import java.text.SimpleDateFormat;
21  import java.util.*;
22  import java.util.regex.Matcher;
23  import java.util.regex.Pattern;
24  
25  /**
26   * Created by pvsubrah on 6/4/15.
27   */
28  public class CheckoutController extends CircUtilController {
29      private static final Logger LOG = Logger.getLogger(CheckoutController.class);
30      private OleLoanDocument currentLoanDocument;
31      private NoticeInfo noticeInfo;
32  
33  
34      public ErrorMessage lookupItemAndSaveLoan(UifFormBase form) {
35          CircForm circForm = (CircForm) form;
36          ErrorMessage errorMessage = null;
37  
38          String itemBarcode = circForm.getItemBarcode();
39  
40          ItemRecord itemRecord = getItemRecordByBarcode(itemBarcode);
41  
42          if (null != itemRecord) {
43              circForm.setItemRecord(itemRecord);
44  
45              if (isNotClaimsReturned(itemRecord) && (isAvailable(itemRecord) || isRecentlyReturned(itemRecord    ))) {
46                  currentLoanDocument = new OleLoanDocument();
47                  noticeInfo = new NoticeInfo();
48  
49                  OleCirculationDesk oleCirculationDesk = getCircDeskLocationResolver().getCircDeskForOpertorId
50                          (GlobalVariables.getUserSession().getPrincipalId());
51                  currentLoanDocument.setOleCirculationDesk(oleCirculationDesk);
52  
53                  List<Object> facts = new ArrayList<>();
54                  OleItemRecordForCirc oleItemRecordForCirc = ItemInfoUtil.getInstance().getOleItemRecordForCirc(itemRecord);
55                  facts.add(oleItemRecordForCirc);
56  
57                  errorMessage = new ErrorMessage();
58                  facts.add(errorMessage);
59  
60                  facts.add(currentLoanDocument);
61  
62                  Map<OlePatronDocument, OlePatronDocument> patronForWhomLoanIsBeingProcessed = identifyPatron(circForm);
63  
64                  facts.add(circForm.getPatronDocument().getSelectedProxyForPatron() == null ? circForm.getPatronDocument() : circForm.getPatronDocument().getSelectedProxyForPatron());
65  
66                  facts.add(noticeInfo);
67  
68                  OleStopWatch oleStopWatch = new OleStopWatch();
69                  oleStopWatch.start();
70                  fireRulesForPatron(facts, null, "checkout validation");
71                  oleStopWatch.end();
72                  LOG.info("Time taken to evaluvate rules for checkout item: " + (oleStopWatch.getTotalTime()) +  " ms");
73  
74                  circForm.setItemValidationDone(true);
75                  setPatronInfForLoanDocument(patronForWhomLoanIsBeingProcessed, currentLoanDocument);
76                  currentLoanDocument.setCirculationLocationId(circForm.getSelectedCirculationDesk());
77                  currentLoanDocument.setItemId(itemRecord.getBarCode());
78                  currentLoanDocument.setItemUuid(itemRecord.getUniqueIdPrefix() + "-" + itemRecord.getItemId());
79                  currentLoanDocument.setCreateDate(new Date(System.currentTimeMillis()));
80                  currentLoanDocument.setLoanOperatorId(getLoginUserId());
81  
82                  processDueDateBasedOnExpirationDate(circForm.getPatronDocument(), currentLoanDocument);
83  
84                  if (null == currentLoanDocument.getCirculationPolicyId()) {
85                      errorMessage.setErrorMessage("No Circulation Policy found that matches the patron/item combination. Please select a due date manually!");
86                      errorMessage.setErrorCode(DroolsConstants.CUSTOM_DUE_DATE_REQUIRED_FLAG);
87                      currentLoanDocument.setCirculationPolicyId("No Circ Policy Found");
88                      noticeInfo.setLoanType(DroolsConstants.REGULAR_LOANS_NOTICE_CONFIG);
89                      return errorMessage;
90                  }
91  
92                  if(null!= errorMessage && StringUtils.isNotBlank(errorMessage.getErrorMessage())){
93                      return errorMessage;
94                  }
95  
96                  proceedToSaveLoan(circForm);
97  
98              } else {
99                  errorMessage = new ErrorMessage();
100                 errorMessage.setErrorMessage("Only Item(s) with \"Available\" status can be checked out using this screen at this time!");
101                 errorMessage.setErrorCode(DroolsConstants.GENERAL_MESSAGE_FLAG);
102             }
103         } else {
104             errorMessage = new ErrorMessage();
105             errorMessage.setErrorMessage("Invalid item barcode : " + itemBarcode);
106             errorMessage.setErrorCode(DroolsConstants.GENERAL_MESSAGE_FLAG);
107         }
108         return errorMessage;
109     }
110 
111     private boolean isRecentlyReturned(ItemRecord itemRecord) {
112         return itemRecord.getItemStatusRecord().getCode().equalsIgnoreCase("RECENTLY-RETURNED");
113     }
114 
115     private boolean isAvailable(ItemRecord itemRecord) {
116         return itemRecord.getItemStatusRecord().getCode().equalsIgnoreCase(OLEConstants.AVAILABLE);
117     }
118 
119     private Map<OlePatronDocument, OlePatronDocument> identifyPatron(CircForm circForm) {
120         Map<OlePatronDocument, OlePatronDocument> patronForWhomLoanIsBeingProcessed = new HashMap<>();
121         OlePatronDocument currentBorrower = circForm.getPatronDocument();
122         if (CollectionUtils.isNotEmpty(currentBorrower.getOleProxyPatronDocumentList())) {
123             if (currentBorrower.isCheckoutForSelf()) {
124                 patronForWhomLoanIsBeingProcessed.put(currentBorrower, null);
125             } else {
126                 List<OleProxyPatronDocument> oleProxyPatronDocumentList = currentBorrower.getOleProxyPatronDocumentList();
127                 for (Iterator<OleProxyPatronDocument> iterator = oleProxyPatronDocumentList.iterator(); iterator.hasNext(); ) {
128                     OleProxyPatronDocument proxyForPatron = iterator.next();
129                     OlePatronDocument proxyForPatronDocument = proxyForPatron.getOlePatronDocument();
130                     if (proxyForPatronDocument.isCheckoutForSelf()) {
131                         patronForWhomLoanIsBeingProcessed.put(proxyForPatronDocument, currentBorrower);
132                     }
133                 }
134             }
135         } else {
136             patronForWhomLoanIsBeingProcessed.put(currentBorrower, null);
137         }
138         return patronForWhomLoanIsBeingProcessed;
139     }
140 
141     private void handleNoticeTablePopulation(ItemRecord itemRecord) {
142         List<Object> facts = new ArrayList<Object>();
143         facts.add(noticeInfo);
144         facts.add(itemRecord);
145 
146         fireRulesForPatron(facts, null, "notice generation");
147 
148         List<OLEDeliverNotice> deliverNotices = processNotices(noticeInfo, currentLoanDocument);
149 
150         //OJB mapping will take care of persisting notice records once the loan document is saved.
151         currentLoanDocument.setDeliverNotices(deliverNotices);
152     }
153 
154 
155     private void setPatronInfForLoanDocument(Map<OlePatronDocument, OlePatronDocument> patronForWhomLoanIsBeingProcessed,
156                                              OleLoanDocument oleLoanDocument) {
157         OlePatronDocument olePatronDocument = patronForWhomLoanIsBeingProcessed.keySet().iterator().next();
158         OlePatronDocument proxyPatron = patronForWhomLoanIsBeingProcessed.get(olePatronDocument);
159 
160         oleLoanDocument.setPatronId(olePatronDocument.getOlePatronId());
161         oleLoanDocument.setRealPatronBarcode(olePatronDocument.getBarcode());
162         if (null != proxyPatron) {
163             oleLoanDocument.setProxyPatronId(proxyPatron.getOlePatronId());
164             oleLoanDocument.setRealPatronName(proxyPatron.getPatronName());
165         }
166     }
167 
168     private boolean isNotClaimsReturned(ItemRecord itemRecord) {
169         Boolean claimsReturnedFlag = itemRecord.getClaimsReturnedFlag();
170         return !(claimsReturnedFlag == null ? false : claimsReturnedFlag.booleanValue());
171     }
172 
173     private void processDueDateBasedOnExpirationDate(OlePatronDocument olePatronDocument, OleLoanDocument
174             oleLoanDocument) {
175         if (olePatronDocument.getExpirationDate() != null && oleLoanDocument.getLoanDueDate() != null) {
176             Timestamp expirationDate = new Timestamp(olePatronDocument.getExpirationDate().getTime());
177             if (isPatronExpiringBeforeLoanDue(oleLoanDocument, expirationDate) && isPatronExpirationGreaterThanToday(expirationDate)) {
178                 oleLoanDocument.setLoanDueDate(expirationDate);
179             }
180         }
181     }
182 
183     private boolean isPatronExpirationGreaterThanToday(Timestamp expirationDate) {
184         return expirationDate.compareTo(new Date()) > 0;
185     }
186 
187     private boolean isPatronExpiringBeforeLoanDue(OleLoanDocument oleLoanDocument, Timestamp expirationDate) {
188         return expirationDate.compareTo(oleLoanDocument.getLoanDueDate()) < 0;
189     }
190 
191     public UifFormBase proceedToSaveLoan(UifFormBase form) {
192         OleStopWatch oleStopWatch = new OleStopWatch();
193         oleStopWatch.start();
194         CircForm circForm = (CircForm) form;
195         ItemRecord itemRecord = circForm.getItemRecord();
196         circForm.getLoanDocumentListForCurrentSession().add(currentLoanDocument);
197 
198         if (processCustomDueDateIfSet(circForm)) return circForm;
199 
200         if (null != currentLoanDocument.getLoanDueDate()) {
201             circForm.getItemRecord().setDueDateTime(currentLoanDocument.getLoanDueDate());
202             handleNoticeTablePopulation(itemRecord);
203         }
204 
205         OleLoanDocument savedLoanDocument = getBusinessObjectService().save(currentLoanDocument);
206         if (null != savedLoanDocument.getLoanId()) {
207             Boolean solrUpdateResults = updateItemInfoInSolr(currentLoanDocument, itemRecord.getItemId());
208             if (solrUpdateResults) {
209                 updateLoanDocumentWithItemInformation(itemRecord, currentLoanDocument);
210                 circForm.getPatronDocument().getOleLoanDocuments().add(currentLoanDocument);
211                 LOG.info("Saved Loan with ID: " + savedLoanDocument.getLoanId());
212             } else {
213                 rollBackSavedLoanRecord(itemRecord.getBarCode());
214                 circForm.getLoanDocumentListForCurrentSession().remove(currentLoanDocument);
215             }
216         } else {
217             circForm.getLoanDocumentListForCurrentSession().clear();
218         }
219         oleStopWatch.end();
220         LOG.info("Time taken to process the loan: " + (oleStopWatch.getTotalTime()) + " ms" );
221         return circForm;
222     }
223 
224     private boolean processCustomDueDateIfSet(CircForm circForm) {
225         if (null != circForm.getCustomDueDateMap()) {
226             try {
227                 processCustomDueDate(circForm);
228             } catch (Exception e) {
229                 return true;
230             }
231         }
232         return false;
233     }
234 
235     private void processCustomDueDate(CircForm circForm) throws Exception {
236         boolean timeFlag = false;
237         Timestamp timestamp;
238         Pattern pattern;
239         Matcher matcher;
240         SimpleDateFormat fmt = new SimpleDateFormat(OLEConstants.OlePatron.PATRON_MAINTENANCE_DATE_FORMAT);
241 
242         String customDueDateTime = circForm.getCustomDueDateTime();
243         Date customDueDateMap = circForm.getCustomDueDateMap();
244 
245         if (StringUtils.isNotBlank(customDueDateTime)) {
246             String[] str = customDueDateTime.split(":");
247             pattern = Pattern.compile(OLEConstants.TIME_24_HR_PATTERN);
248             matcher = pattern.matcher(customDueDateTime);
249             timeFlag = matcher.matches();
250             if (timeFlag) {
251                 if (str != null && str.length <= 2) {
252                     circForm.setCustomDueDateTime(customDueDateTime + OLEConstants.CHECK_IN_TIME_MS);
253                 }
254                 timestamp = Timestamp.valueOf(new SimpleDateFormat(OLEConstants.CHECK_IN_DATE_TIME_FORMAT).format(customDueDateMap).concat(" ").concat(customDueDateTime));
255             } else {
256                 circForm.setCustomDueDateTimeMessage(OLEConstants.DUE_DATE_TIME_FORMAT_MESSAGE);
257                 throw new Exception();
258             }
259         } else if (fmt.format(customDueDateMap).compareTo(fmt.format(new Date())) == 0) {
260             timestamp = new Timestamp(new Date().getTime());
261         } else {
262             timestamp = Timestamp.valueOf(new SimpleDateFormat(OLEConstants.CHECK_IN_DATE_TIME_FORMAT).format(customDueDateMap).concat(" ").concat(new SimpleDateFormat("HH:mm:ss").format(new Date())));
263         }
264         currentLoanDocument.setLoanDueDate(timestamp);
265         currentLoanDocument.setCirculationPolicyId("No Circulation Policy Matched");
266     }
267 }