View Javadoc
1   /*
2    * Copyright (c) 2002-2018, Mairie de Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.plugins.stock.modules.billetterie.web;
35  
36  import fr.paris.lutece.plugins.stock.business.purchase.PurchaseFilter;
37  import fr.paris.lutece.plugins.stock.business.purchase.exception.PurchaseUnavailable;
38  import fr.paris.lutece.plugins.stock.commons.ResultList;
39  import fr.paris.lutece.plugins.stock.commons.dao.PaginationProperties;
40  import fr.paris.lutece.plugins.stock.commons.exception.BusinessException;
41  import fr.paris.lutece.plugins.stock.commons.exception.FunctionnalException;
42  import fr.paris.lutece.plugins.stock.modules.billetterie.utils.constants.BilletterieConstants;
43  import fr.paris.lutece.plugins.stock.modules.tickets.business.NotificationDTO;
44  import fr.paris.lutece.plugins.stock.modules.tickets.business.ReservationDTO;
45  import fr.paris.lutece.plugins.stock.modules.tickets.business.ReservationFilter;
46  import fr.paris.lutece.plugins.stock.modules.tickets.business.SeanceDTO;
47  import fr.paris.lutece.plugins.stock.modules.tickets.business.SeanceFilter;
48  import fr.paris.lutece.plugins.stock.modules.tickets.service.INotificationService;
49  import fr.paris.lutece.plugins.stock.modules.tickets.service.IPurchaseService;
50  import fr.paris.lutece.plugins.stock.modules.tickets.service.ISeanceService;
51  import fr.paris.lutece.plugins.stock.modules.tickets.utils.constants.TicketsConstants;
52  import fr.paris.lutece.plugins.stock.service.IPurchaseSessionManager;
53  import fr.paris.lutece.plugins.stock.utils.DateUtils;
54  import fr.paris.lutece.plugins.stock.utils.ListUtils;
55  import fr.paris.lutece.plugins.stock.utils.NumberUtils;
56  import fr.paris.lutece.plugins.stock.utils.constants.StockConstants;
57  import fr.paris.lutece.portal.business.user.AdminUser;
58  import fr.paris.lutece.portal.business.user.AdminUserHome;
59  import fr.paris.lutece.portal.service.i18n.I18nService;
60  import fr.paris.lutece.portal.service.message.AdminMessage;
61  import fr.paris.lutece.portal.service.message.AdminMessageService;
62  import fr.paris.lutece.portal.service.spring.SpringContextService;
63  import fr.paris.lutece.portal.service.template.AppTemplateService;
64  import fr.paris.lutece.portal.service.util.AppLogService;
65  import fr.paris.lutece.portal.service.util.AppPathService;
66  import fr.paris.lutece.portal.service.util.AppPropertiesService;
67  import fr.paris.lutece.portal.web.constants.Parameters;
68  import fr.paris.lutece.util.ReferenceItem;
69  import fr.paris.lutece.util.ReferenceList;
70  import fr.paris.lutece.util.datatable.DataTableManager;
71  import fr.paris.lutece.util.html.HtmlTemplate;
72  import fr.paris.lutece.util.url.UrlItem;
73  
74  import org.apache.commons.lang.StringUtils;
75  
76  import org.apache.log4j.Logger;
77  
78  import java.io.IOException;
79  
80  import java.lang.reflect.Method;
81  
82  import java.util.ArrayList;
83  import java.util.Collection;
84  import java.util.HashMap;
85  import java.util.List;
86  import java.util.Locale;
87  import java.util.Map;
88  
89  import javax.servlet.http.HttpServletRequest;
90  import javax.servlet.http.HttpServletResponse;
91  
92  /**
93   * This class provides the user interface to manage form features ( manage, create, modify, remove)
94   */
95  public class PurchaseJspBean extends AbstractJspBean
96  {
97      /** The logger for this jspBean */
98      public static final Logger LOGGER = Logger.getLogger( PurchaseJspBean.class );
99  
100     /** The constant String RESOURCE_TYPE */
101     public static final String RESOURCE_TYPE = "STOCK";
102 
103     /** The constant String RIGHT_MANAGE_PURCHASES */
104     public static final String RIGHT_MANAGE_PURCHASES = "PURCHASES_MANAGEMENT";
105 
106     // PARAMETERS
107     /** The constant String PARAMETER_PURCHASE_ID */
108     public static final String PARAMETER_PURCHASE_ID = "purchase_id";
109 
110     /** The constant String PARAMETER_PURCHASE_DUPLICATE */
111     public static final String PARAMETER_PURCHASE_DUPLICATE = "duplicate";
112 
113     /** The constant String PARAMETER_PURCHASE_PRODUCT_NAME */
114     public static final String PARAMETER_PURCHASE_PRODUCT_NAME = "productName";
115 
116     /** The constant String PARAMETER_PURCHASE_GENRE_LIST */
117     public static final String PARAMETER_PURCHASE_GENRE_LIST = "purchase_genre_list";
118 
119     /** The constant String PARAMETER_PURCHASE_GENRE_LIST_DEFAULT */
120     public static final String PARAMETER_PURCHASE_GENRE_LIST_DEFAULT = "purchase_genre_list_default";
121 
122     /** The constant String PARAMETER_BUTTON_DELETE */
123     public static final String PARAMETER_BUTTON_DELETE = "delete";
124 
125     /** The constant String PARAMETER_FILTER_NAME */
126     public static final String PARAMETER_FILTER_NAME = "filter_name";
127 
128     /** The constant String PARAMETER_FILTER_ID */
129     public static final String PARAMETER_FILTER_ID = "filter_id";
130 
131     /** The constant String PARAMETER_FILTER_PARTNER_NAME */
132     public static final String PARAMETER_FILTER_PARTNER_NAME = "filter_partner_name";
133 
134     /** The constant String PARAMETER_FILTER_PARTNER_NICKNAME */
135     public static final String PARAMETER_FILTER_PARTNER_NICKNAME = "filter_partner_nickname";
136 
137     /** The constant String PARAMETER_FILTER_PURCHASE_TYPE */
138     public static final String PARAMETER_FILTER_PURCHASE_TYPE = "filter_purchase_type";
139 
140     /** The constant String PARAMETER_FILTER_DATE_BEGIN */
141     public static final String PARAMETER_FILTER_DATE_BEGIN = "filter_date_begin";
142 
143     /** The constant String PARAMETER_FILTER_DATE_END */
144     public static final String PARAMETER_FILTER_DATE_END = "filter_date_end";
145 
146     /** The constant String PARAMETER_ORDER_BY_ID */
147     public static final String PARAMETER_ORDER_BY_ID = "order_by_id";
148 
149     /** The constant String PARAMETER_ORDER_BY_LABEL */
150     public static final String PARAMETER_ORDER_BY_LABEL = "order_by_label";
151 
152     /** The constant String PARAMETER_ORDER_BY_PLACE */
153     public static final String PARAMETER_ORDER_BY_PLACE = "order_by_place";
154 
155     /** The constant String PARAMETER_ORDER_BY_TYPE */
156     public static final String PARAMETER_ORDER_BY_TYPE = "order_by_type";
157 
158     /** The constant String PARAMETER_ORDER_ASC */
159     public static final String PARAMETER_ORDER_ASC = "order_asc";
160 
161     /** The constant String PARAMETER_ORDER_DESC */
162     public static final String PARAMETER_ORDER_DESC = "order_desc";
163 
164     /** The constant String PARAMETER_FILTER */
165     public static final String PARAMETER_FILTER = "filter";
166     private static final String PARAMETER_PURCHASES_ID = "purchases_id";
167 
168     // MARKS
169 
170     /** The constants for DataTableManager */
171     public static final String MARK_DATA_TABLE_PURCHASE = "dataTablePurchase";
172     public static final String MARK_FILTER_PURCHASE = "filterPurchase";
173     public static final String MACRO_COLUMN_ACTIONS_PURCHASE = "columnActionsPurchase";
174     public static final String MACRO_COLUMN_NAME_PURCHASE = "columnNamePurchase";
175     public static final String MACRO_COLUMN_DATE_PURCHASE = "columnDatePurchase";
176     public static final String MACRO_COLUMN_OFFER_TYPE_PURCHASE = "columnOfferTypePurchase";
177     public static final String MACRO_COLUMN_CHECKBOX_DELETE_PURCHASE = "columnCheckboxDeletePurchase";
178     public static final String MACRO_COLUMN_AGENT_PURCHASE = "columnAgentPurchase";
179 
180     /** The constant String MARK_PURCHASE */
181     public static final String MARK_PURCHASE = "purchase";
182 
183     /** The constant String MARK_TITLE */
184     public static final String MARK_TITLE = "title";
185 
186     /** The constant String MARK_LOCALE */
187     public static final String MARK_LOCALE = "locale";
188 
189     /** The constant String MARK_PURCHASE_STATUT_CANCEL */
190     public static final String MARK_PURCHASE_STATUT_CANCEL = "strStatutCancel";
191 
192     /** The constant String MARK_CURRENT_DATE */
193     public static final String MARK_CURRENT_DATE = "currentDate";
194 
195     /** The constant String MARK_LIST_OFFER_GENRE */
196     public static final String MARK_LIST_OFFER_GENRE = "offerGenre_list";
197 
198     /** The constant String MARK_OFFER_ID */
199     public static final String MARK_OFFER_ID = "offer_id";
200 
201     /** The constant String MARK_PURCHASSE_ID */
202     public static final String MARK_PURCHASSE_ID = "purchase_id";
203 
204     /** The constant String MARK_QUANTITY_LIST */
205     public static final String MARK_QUANTITY_LIST = "quantity_list";
206 
207     /** The constant String MARK_ERRORS */
208     public static final String MARK_ERRORS = "errors";
209 
210     /** The constant String MARK_BASE_URL */
211     public static final String MARK_BASE_URL = "base_url";
212     public static final String MARK_OFFERS_AVAILABLES = "offers_availables";
213     public static final String MARK_NEW_ID_OFFER = "newIdOffer";
214 
215     /** The constant String MARK_SEANCE */
216     public static final String MARK_SEANCE = "seance";
217 
218     // BEANS
219     private static final String BEAN_STOCK_TICKETS_SEANCE_SERVICE = "stock-tickets.seanceService";
220 
221     // JSP
222     private static final String JSP_MANAGE_PURCHASES = "jsp/admin/plugins/stock/modules/billetterie/ManagePurchase.jsp";
223     private static final String JSP_DO_DELETE_PURCHASE = "jsp/admin/plugins/stock/modules/billetterie/DoDeletePurchase.jsp";
224     private static final String JSP_MANAGE_OFFERS = "jsp/admin/plugins/stock/modules/billetterie/ManageOffers.jsp";
225     private static final String JSP_SAVE_PURCHASE = "SavePurchase.jsp";
226     private static final String JSP_DO_NOTIFY_PURCHASE = "jsp/admin/plugins/stock/modules/billetterie/DoNotifyPurchase.jsp";
227 
228     // TEMPLATES
229     private static final String TEMPLATE_MANAGE_PURCHASES = "admin/plugins/stock/modules/billetterie/manage_purchases.html";
230     private static final String TEMPLATE_SAVE_PURCHASE = "admin/plugins/stock/modules/billetterie/save_purchase.html";
231     private static final String TEMPLATE_NOTIFICATION_BOOKING = "admin/plugins/stock/modules/billetterie/notification_booking.html";
232     private static final String TEMPLATE_NOTIFICATION_ADMIN_OFFER_QUANTITY = "notification_admin_offer_quantity.html";
233 
234     // PAGE TITLES
235     private static final String PROPERTY_PAGE_TITLE_MANAGE_PURCHASE = "module.stock.billetterie.list_purchase.title";
236     private static final String PROPERTY_PAGE_TITLE_CREATE_PURCHASE = "module.stock.billetterie.create_purchase.title";
237     private static final String PROPERTY_PAGE_TITLE_MODIFY_PURCHASE = "module.stock.billetterie.modify_purchase.title";
238 
239     // MESSAGES
240     private static final String MESSAGE_CONFIRMATION_DELETE_PURCHASE = "module.stock.billetterie.message.deletePurchase.confirmation";
241     private static final String MESSAGE_CONFIRMATION_MASSE_DELETE_PURCHASE = "module.stock.billetterie.message.deletePurchase.masseConfirmation";
242     private static final String MESSAGE_INSUFFICIENT_PLACE_REMAINING = "module.stock.billetterie.message.error.insufficient_place_remaining";
243     private static final String MESSAGE_TITLE_CONFIRMATION_DELETE_PURCHASE = "module.stock.billetterie.message.title.deletePurchase.confirmation";
244     private static final String MESSAGE_SEARCH_OFFER_DATE = "module.stock.billetterie.message.search.offer.date";
245     private static final String MESSAGE_SEARCH_PURCHASE_DATE = "module.stock.billetterie.message.search.purchase.date";
246     private static final String MESSAGE_NOTIFICATION_BOOKING_SUBJECT = "module.stock.billetterie.notification.booking.subject";
247     private static final String MESSAGE_NOTIFY_PURCHASE_CONFIRMATION = "module.stock.billetterie.message.notifyPurchase.confirmation";
248     private static final String MESSAGE_TITLE_NOTIFY_PURCHASE_CONFIRMATION = "module.stock.billetterie.message.title.notifyPurchase.confirmation";
249     private static final String MESSAGE_DELETE_MASSE_PURCHASE_NO_CHECK = "module.stock.billetterie.message.deleteMassePurchase.noCaseCheck";
250     private static final String MESSAGE_NOTIFICATION_ADMIN_OFFER_QUANTITY_SUBJECT = "module.stock.billetterie.notification.admin.offer.quantity.subject";
251 
252     // ORDER FILTERS
253     private static final String ORDER_FILTER_DATE = "date";
254     private static final String ORDER_FILTER_OFFER_TYPE_NAME = "offer.typeName";
255     private static final String ORDER_FILTER_OFFER_DATE = "offer.date";
256     private static final String ORDER_FILTER_OFFER_PRODUCT_NAME = "offer.product.name";
257 
258     // MEMBERS VARIABLES
259     // @Inject
260     private IPurchaseService _servicePurchase;
261 
262     // @Inject
263     // @Named( "stock-tickets.seanceService" )
264     private ISeanceService _serviceOffer;
265 
266     // @Inject
267     private IPurchaseSessionManager _purchaseSessionManager;
268     private ReservationFilter _purchaseFilter;
269     private INotificationService _serviceNotification;
270 
271     /**
272      * Instantiates a new purchase jsp bean.
273      */
274     public PurchaseJspBean( )
275     {
276         super( );
277 
278         _purchaseFilter = new ReservationFilter( );
279         _servicePurchase = SpringContextService.getContext( ).getBean( IPurchaseService.class );
280         _serviceOffer = (ISeanceService) SpringContextService.getBean( BEAN_STOCK_TICKETS_SEANCE_SERVICE );
281         _purchaseSessionManager = SpringContextService.getContext( ).getBean( IPurchaseSessionManager.class );
282         _serviceNotification = SpringContextService.getContext( ).getBean( INotificationService.class );
283     }
284 
285     /**
286      * Builds the filter.
287      *
288      * @param filter
289      *            the filter
290      * @param request
291      *            the request
292      */
293     protected void buildFilter( ReservationFilter filter, HttpServletRequest request )
294     {
295         populate( filter, request );
296     }
297 
298     /**
299      * Gets the purchase filter.
300      *
301      * @param request
302      *            the request
303      * @return the purchase filter
304      */
305     private ReservationFilter getPurchaseFilter( HttpServletRequest request )
306     {
307         // SORT
308         String strSortedAttributeName = request.getParameter( Parameters.SORTED_ATTRIBUTE_NAME );
309 
310         ReservationFilter filter = new ReservationFilter( );
311 
312         // "filter" in request ==> new filter. use old one otherwise
313         if ( request.getParameter( TicketsConstants.PARAMETER_FILTER ) != null )
314         {
315             // ReservationFilter filter = new ReservationFilter( );
316             buildFilter( filter, request );
317             // _purchaseFilter = filter;
318         }
319 
320         _purchaseFilter = filter;
321 
322         if ( strSortedAttributeName != null )
323         {
324             _purchaseFilter.getOrders( ).add( strSortedAttributeName );
325 
326             String strAscSort = request.getParameter( Parameters.SORTED_ASC );
327             boolean bIsAscSort = Boolean.parseBoolean( strAscSort );
328             _purchaseFilter.setOrderAsc( bIsAscSort );
329         }
330 
331         return _purchaseFilter;
332     }
333 
334     /**
335      * Get the manage purchases page
336      *
337      * @param request
338      *            the request
339      * @return the page with purchases list
340      */
341     public String getManagePurchases( HttpServletRequest request )
342     {
343         setPageTitleProperty( PROPERTY_PAGE_TITLE_MANAGE_PURCHASE );
344 
345         Map<String, Object> model = new HashMap<String, Object>( );
346         ReservationFilter filter = getPurchaseFilter( request );
347 
348         // if date begin is after date end, add error
349         List<String> error = new ArrayList<String>( );
350 
351         if ( ( filter.getDateBeginOffer( ) != null ) && ( filter.getDateEndOffer( ) != null ) && filter.getDateBeginOffer( ).after( filter.getDateEndOffer( ) ) )
352         {
353             error.add( I18nService.getLocalizedString( MESSAGE_SEARCH_OFFER_DATE, request.getLocale( ) ) );
354         }
355 
356         if ( ( filter.getDateBegin( ) != null ) && ( filter.getDateEnd( ) != null ) && filter.getDateBegin( ).after( filter.getDateEnd( ) ) )
357         {
358             error.add( I18nService.getLocalizedString( MESSAGE_SEARCH_PURCHASE_DATE, request.getLocale( ) ) );
359         }
360 
361         model.put( MARK_ERRORS, error );
362 
363         // OrderList for purchase list
364         List<String> orderList = new ArrayList<String>( );
365         orderList.add( ORDER_FILTER_DATE );
366         orderList.add( ORDER_FILTER_OFFER_PRODUCT_NAME );
367         orderList.add( ORDER_FILTER_OFFER_DATE );
368         orderList.add( ORDER_FILTER_OFFER_TYPE_NAME );
369         filter.setOrders( orderList );
370         filter.setOrderAsc( true );
371 
372         String strOfferId = request.getParameter( MARK_OFFER_ID );
373         String purchaseId = request.getParameter( MARK_PURCHASSE_ID );
374         boolean forceNewFilter = false;
375 
376         if ( strOfferId != null )
377         {
378             SeanceDTO seance = this._serviceOffer.findSeanceById( Integer.parseInt( strOfferId ) );
379 
380             if ( StringUtils.isNotEmpty( purchaseId ) && NumberUtils.validateInt( purchaseId ) )
381             {
382                 ReservationDTO reservation = this._servicePurchase.findById( Integer.parseInt( purchaseId ) );
383                 filter.setUserName( reservation.getUserName( ) );
384             }
385 
386             filter.setIdOffer( seance.getId( ) );
387             filter.setProductName( seance.getProduct( ).getName( ) );
388             filter.setIdGenre( seance.getIdGenre( ) );
389             filter.setDateBeginOffer( DateUtils.getDate( seance.getDate( ), false ) );
390             filter.setDateEndOffer( DateUtils.getDate( seance.getDate( ), false ) );
391 
392             forceNewFilter = true;
393         }
394 
395         // Obtention des objets sauvegardés en session
396         DataTableManager<ReservationDTO> dataTableToUse = getDataTable( request, filter, forceNewFilter );
397         model.put( MARK_DATA_TABLE_PURCHASE, dataTableToUse );
398 
399         // Fill the model
400         model.put( MARK_LOCALE, getLocale( ) );
401 
402         // Combo
403         ReferenceList offerGenreComboList = ListUtils.toReferenceList( _serviceOffer.findAllGenre( ), BilletterieConstants.ID, BilletterieConstants.NAME,
404                 StockConstants.EMPTY_STRING );
405         model.put( MARK_LIST_OFFER_GENRE, offerGenreComboList );
406         // offer statut cancel
407         model.put( MARK_PURCHASE_STATUT_CANCEL, TicketsConstants.OFFER_STATUT_CANCEL );
408         // the filter
409         model.put( TicketsConstants.MARK_FILTER, filter );
410 
411         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_MANAGE_PURCHASES, getLocale( ), model );
412         // opération nécessaire pour eviter les fuites de mémoires
413         dataTableToUse.clearItems( );
414 
415         return getAdminPage( template.getHtml( ) );
416     }
417 
418     /**
419      * Get the DataTableManager object for the ReservationDTO bean
420      * 
421      * @param request
422      *            the http request
423      * @param filter
424      *            the filter
425      * @param <T>
426      *            the type of the bean
427      * @return the data table to use
428      */
429     private <T> DataTableManager<T> getDataTable( HttpServletRequest request, PurchaseFilter filter, boolean forceNewFilter )
430     {
431         // si un objet est déjà présent en session, on l'utilise
432         Method findMethod = null;
433 
434         try
435         {
436             findMethod = _servicePurchase.getClass( ).getMethod( PARAMETER_FIND_BY_FILTER_NAME_METHOD, PurchaseFilter.class, PaginationProperties.class );
437         }
438         catch( Exception e )
439         {
440             LOGGER.error( "Erreur lors de l'obtention du data table : ", e );
441         }
442 
443         DataTableManager<T> dataTableToUse = getAbstractDataTableManager( request, filter, MARK_DATA_TABLE_PURCHASE, JSP_MANAGE_PURCHASES, _servicePurchase,
444                 findMethod, forceNewFilter );
445 
446         // si pas d'objet en session, il faut ajouter les colonnes à afficher
447         if ( dataTableToUse.getListColumn( ).isEmpty( ) )
448         {
449             dataTableToUse.addFreeColumn( StringUtils.EMPTY, MACRO_COLUMN_CHECKBOX_DELETE_PURCHASE );
450             dataTableToUse.addColumn( "module.stock.billetterie.list_purchase.table.product", "offer.product.name", true );
451             dataTableToUse.addFreeColumn( "module.stock.billetterie.list_purchase.table.dateOffer", MACRO_COLUMN_DATE_PURCHASE );
452             dataTableToUse.addColumn( "module.stock.billetterie.list_purchase.table.datePurchase", "date", false );
453             dataTableToUse.addColumn( "module.stock.billetterie.list_purchase.table.typeOffer", "offer.typeName", true );
454             dataTableToUse.addFreeColumn( "module.stock.billetterie.list_purchase.table.userName", MACRO_COLUMN_AGENT_PURCHASE );
455             dataTableToUse.addColumn( "module.stock.billetterie.list_purchase.table.quantity", "quantity", false );
456             dataTableToUse.addFreeColumn( "module.stock.billetterie.list_purchase.table.actions", MACRO_COLUMN_ACTIONS_PURCHASE );
457         }
458 
459         saveDataTableInSession( request, dataTableToUse, MARK_DATA_TABLE_PURCHASE );
460 
461         return dataTableToUse;
462     }
463 
464     /**
465      * Returns the form for purchase creation and modification
466      * 
467      * @param request
468      *            The HTTP request
469      * @param response
470      *            The HTTP response
471      * @return HTML Form
472      */
473     public String getSavePurchase( HttpServletRequest request, HttpServletResponse response )
474     {
475         ReservationDTO purchase = null;
476         Map<String, Object> model = new HashMap<String, Object>( );
477         model.put( MARK_LOCALE, getLocale( ) );
478 
479         String strIdOffer;
480         String strIdPurchase = request.getParameter( MARK_PURCHASSE_ID );
481         boolean modeModification = StringUtils.isNotBlank( strIdPurchase );
482 
483         // Manage validation errors
484         FunctionnalException ve = getErrorOnce( request );
485 
486         if ( ve != null )
487         {
488             purchase = (ReservationDTO) ve.getBean( );
489             model.put( BilletterieConstants.ERROR, getHtmlError( ve ) );
490             strIdOffer = purchase.getOffer( ).getId( ).toString( );
491         }
492         else
493         {
494             strIdOffer = request.getParameter( MARK_OFFER_ID );
495             setPageTitleProperty( PROPERTY_PAGE_TITLE_CREATE_PURCHASE );
496             // Create new Purchase
497             purchase = new ReservationDTO( );
498         }
499 
500         // modification page only
501         if ( strIdPurchase != null )
502         {
503             Integer nIdPurchase = Integer.parseInt( strIdPurchase );
504 
505             // get the info of the purchase
506             purchase = _servicePurchase.findById( nIdPurchase );
507             strIdOffer = purchase.getOfferId( ).toString( );
508             model.put( MARK_PURCHASSE_ID, nIdPurchase );
509         }
510 
511         if ( strIdOffer != null )
512         {
513             Integer idOffer = Integer.parseInt( strIdOffer );
514 
515             // affectation de la représentation, soit la même (creation) soit celle issue d'un refresh
516             SeanceDTO seance = this._serviceOffer.findSeanceById( idOffer );
517             purchase.setOffer( seance );
518 
519             _purchaseSessionManager.release( request.getSession( ).getId( ), purchase );
520 
521             Integer quantity = Integer.MAX_VALUE;
522             quantity = maximizeQuantity( seance, quantity );
523 
524             // Update quantity with quantity in session for this offer
525             if ( quantity > seance.getQuantity( ) )
526             {
527                 quantity = seance.getQuantity( );
528             }
529 
530             quantity = _purchaseSessionManager.updateQuantityWithSession( quantity, idOffer );
531 
532             seance.setQuantity( quantity );
533 
534             ReferenceList quantityList = new ReferenceList( );
535 
536             for ( Integer i = 1; i <= quantity; i++ )
537             {
538                 ReferenceItem refItem = new ReferenceItem( );
539                 refItem.setCode( i.toString( ) );
540                 refItem.setName( i.toString( ) );
541                 quantityList.add( refItem );
542             }
543 
544             model.put( MARK_QUANTITY_LIST, quantityList );
545 
546             // Reserve tickets
547             try
548             {
549                 // dans le cas d'une creation, vérification du nombre de place disponible, s'il n'est pas suffisant, on affiche une erreur
550                 if ( !modeModification && ( quantity == 0 ) )
551                 {
552                     throw new PurchaseUnavailable( purchase.getId( ), MESSAGE_INSUFFICIENT_PLACE_REMAINING );
553                 }
554 
555                 if ( purchase.getQuantity( ) == null )
556                 {
557                     purchase.setQuantity( quantity );
558                 }
559 
560                 if ( !modeModification )
561                 {
562                     _purchaseSessionManager.reserve( request.getSession( ).getId( ), purchase );
563                 }
564             }
565             catch( PurchaseUnavailable e )
566             {
567                 try
568                 {
569                     response.sendRedirect( AdminMessageService.getMessageUrl( request, MESSAGE_INSUFFICIENT_PLACE_REMAINING, AdminMessage.TYPE_STOP ) );
570                 }
571                 catch( IOException e1 )
572                 {
573                     AppLogService.error( e1 );
574                 }
575 
576                 return null;
577             }
578 
579             // dans le cas d'une modification, il faut afficher les representations disponibles
580             if ( modeModification )
581             {
582                 SeanceFilter filter = new SeanceFilter( );
583                 filter.setDateBegin( DateUtils.getCurrentDate( ) );
584                 filter.setProductId( seance.getProduct( ).getId( ) );
585 
586                 ResultList<SeanceDTO> offerAvailables = _serviceOffer.findByFilter( filter, null );
587                 model.put( MARK_OFFERS_AVAILABLES, offerAvailables );
588             }
589         }
590 
591         // Add the JSP wich called this action
592         model.put( StockConstants.MARK_JSP_BACK, JSP_MANAGE_OFFERS );
593         model.put( MARK_PURCHASE, purchase );
594 
595         if ( ( strIdPurchase != null ) || ( purchase.getId( ) != null ) )
596         {
597             setPageTitleProperty( PROPERTY_PAGE_TITLE_MODIFY_PURCHASE );
598             model.put( MARK_TITLE, I18nService.getLocalizedString( PROPERTY_PAGE_TITLE_MODIFY_PURCHASE, Locale.getDefault( ) ) );
599         }
600         else
601         {
602             model.put( MARK_TITLE, I18nService.getLocalizedString( PROPERTY_PAGE_TITLE_CREATE_PURCHASE, Locale.getDefault( ) ) );
603         }
604 
605         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_SAVE_PURCHASE, getLocale( ), model );
606 
607         return getAdminPage( template.getHtml( ) );
608     }
609 
610     /**
611      * Ensures that quantity are not null and not bigger than maximum define
612      * 
613      * @param seance
614      *            the seance with quantity to check
615      * @param actualQuantity
616      *            the actual quantity
617      * @return the maximized quantity
618      */
619     private Integer maximizeQuantity( SeanceDTO seance, Integer actualQuantity )
620     {
621         actualQuantity = Math.min( actualQuantity, seance.getMaxTickets( ) );
622 
623         return actualQuantity;
624     }
625 
626     /**
627      * Save a purchase
628      * 
629      * @param request
630      *            The HTTP request
631      * @return redirection url
632      */
633     public String doSavePurchase( HttpServletRequest request )
634     {
635         ReservationDTO purchase = new ReservationDTO( );
636         String strIdPurchase = request.getParameter( PARAMETER_PURCHASE_ID );
637 
638         // Dans le cas d'une modification, on actualise la reservation avec les nouvelles informations "textuels" (informations sur l'agent)
639         if ( StringUtils.isNotBlank( strIdPurchase ) )
640         {
641             // case of modification
642             Integer nIdPurchase = Integer.parseInt( strIdPurchase );
643             purchase = _servicePurchase.findById( nIdPurchase );
644             populate( purchase, request );
645         }
646         else
647         {
648             // case of creation, les informations sont récupérés et l'objet est préparé pour une création
649             populate( purchase, request );
650             purchase.setDate( DateUtils.getCurrentDateString( ) );
651         }
652 
653         // redirection si necessaire au lieu d'enregistrer la reservation
654         if ( null != request.getParameter( StockConstants.PARAMETER_BUTTON_CANCEL ) )
655         {
656             return doCancelPurchase( request, purchase );
657         }
658 
659         try
660         {
661             // Controls mandatory fields
662             validateBilletterie( purchase );
663 
664             // si le champs sont valide
665             try
666             {
667                 // Reserve tickets
668                 // Libère la réservation prévue sur la page de réservation
669                 _purchaseSessionManager.release( request.getSession( ).getId( ), purchase );
670 
671                 if ( purchase.getId( ) != null )
672                 {
673                     _servicePurchase.doDeletePurchase( purchase.getId( ) );
674                     purchase.setId( null );
675                 }
676 
677                 // Réserve avec les nouvelles valeurs saisies par l'utilisateur
678                 // si la quantité n'est pas présente dans la requete, c'est que l'utilisateur n'a pas modifié le nombre de place voulu
679                 // dans ce cas, il faut réallouer des places au purchasesessionmanager
680                 _purchaseSessionManager.reserve( request.getSession( ).getId( ), purchase );
681             }
682             catch( PurchaseUnavailable e )
683             {
684                 throw new BusinessException( purchase, MESSAGE_INSUFFICIENT_PLACE_REMAINING );
685             }
686 
687             // le test vient d'être fait quant à la possibilité de faire cette réservation, il faut donc la créer ou mettre à jour l'ancienne
688             _servicePurchase.doSavePurchase( purchase, request.getSession( ).getId( ) );
689 
690             // Send a notification when the remaining tickets cannot be purchased
691             sendNotificationToAdmins( request, purchase );
692         }
693         catch( FunctionnalException e )
694         {
695             return manageFunctionnalException( request, e, JSP_SAVE_PURCHASE );
696         }
697 
698         UrlItem redirection = new UrlItem( AppPathService.getBaseUrl( request ) + JSP_MANAGE_PURCHASES );
699         redirection.addParameter( MARK_OFFER_ID, purchase.getOffer( ).getId( ) );
700         redirection.addParameter( MARK_PURCHASSE_ID, purchase.getId( ) );
701 
702         return redirection.getUrl( );
703     }
704 
705     /**
706      * Send a notification to all the admins when all the tickets of an offer are booked
707      * 
708      * @param request
709      *            The HTTP request
710      * @param purchase
711      */
712     private void sendNotificationToAdmins( HttpServletRequest request, ReservationDTO purchase )
713     {
714         SeanceDTO seance = this._serviceOffer.findSeanceById( purchase.getOffer( ).getId( ) );
715 
716         if ( seance != null && seance.getQuantity( ) < seance.getMinTickets( ) )
717         {
718             // Generate mail content
719             Map<String, Object> model = new HashMap<String, Object>( );
720             model.put( MARK_SEANCE, seance );
721             model.put( MARK_BASE_URL, AppPathService.getBaseUrl( request ) );
722 
723             HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_NOTIFICATION_ADMIN_OFFER_QUANTITY, request.getLocale( ), model );
724 
725             Collection<AdminUser> listUsers = (List<AdminUser>) AdminUserHome.findUserList( );
726 
727             for ( AdminUser adminUser : listUsers )
728             {
729                 // Create mail object
730                 NotificationDTO notificationDTO = new NotificationDTO( );
731                 notificationDTO.setRecipientsTo( adminUser.getEmail( ) );
732 
733                 String [ ] args = new String [ ] {
734                     String.valueOf( seance.getId( ) )
735                 };
736                 notificationDTO.setSubject( I18nService.getLocalizedString( MESSAGE_NOTIFICATION_ADMIN_OFFER_QUANTITY_SUBJECT, args, request.getLocale( ) ) );
737                 notificationDTO.setMessage( template.getHtml( ) );
738 
739                 // Send it
740                 _serviceNotification.send( notificationDTO );
741             }
742         }
743     }
744 
745     /**
746      * Return the url of the JSP which called the last action and release reservation from session
747      * 
748      * @param request
749      *            The Http request
750      * @param purchase
751      *            the purchase to cancel
752      * @return The url of the last JSP
753      */
754     private String doCancelPurchase( HttpServletRequest request, ReservationDTO purchase )
755     {
756         // Libère la réservation prévue sur la page de réservation
757         _purchaseSessionManager.release( request.getSession( ).getId( ), purchase );
758 
759         String strJspBack = request.getParameter( StockConstants.MARK_JSP_BACK );
760 
761         return  ( AppPathService.getBaseUrl( request ) + JSP_MANAGE_PURCHASES );
762     }
763 
764     /**
765      * Return the url of the JSP which called the last action
766      * 
767      * @param request
768      *            The Http request
769      * @return The url of the last JSP
770      */
771     private String doGoBack( HttpServletRequest request )
772     {
773         String strJspBack = request.getParameter( StockConstants.MARK_JSP_BACK );
774 
775         return StringUtils.isNotBlank( strJspBack ) ? ( AppPathService.getBaseUrl( request ) + strJspBack )
776                 : ( AppPathService.getBaseUrl( request ) + JSP_MANAGE_PURCHASES );
777     }
778 
779     /**
780      * Returns the confirmation message to delete an purchase
781      *
782      * @param request
783      *            The Http request
784      * @return the html code message
785      */
786     public String getDeletePurchase( HttpServletRequest request )
787     {
788         String strPurchaseId = request.getParameter( PARAMETER_PURCHASE_ID );
789 
790         Integer nIdPurchase;
791 
792         try
793         {
794             nIdPurchase = Integer.parseInt( strPurchaseId );
795         }
796         catch( NumberFormatException e )
797         {
798             LOGGER.debug( e );
799 
800             return AdminMessageService.getMessageUrl( request, StockConstants.MESSAGE_ERROR_OCCUR, AdminMessage.TYPE_STOP );
801         }
802 
803         Map<String, Object> urlParam = new HashMap<String, Object>( );
804         urlParam.put( PARAMETER_PURCHASE_ID, nIdPurchase );
805 
806         String strJspBack = JSP_MANAGE_PURCHASES;
807 
808         return AdminMessageService.getMessageUrl( request, MESSAGE_CONFIRMATION_DELETE_PURCHASE, null, MESSAGE_TITLE_CONFIRMATION_DELETE_PURCHASE,
809                 JSP_DO_DELETE_PURCHASE, BilletterieConstants.TARGET_SELF, AdminMessage.TYPE_CONFIRMATION, urlParam, strJspBack );
810     }
811 
812     /**
813      * Delete an purchase
814      *
815      * @param request
816      *            The Http request
817      * @return the html code message
818      */
819     public String doDeletePurchase( HttpServletRequest request )
820     {
821         String strPurchaseId = request.getParameter( PARAMETER_PURCHASE_ID );
822         Integer nIdPurchase;
823 
824         if ( strPurchaseId != null )
825         {
826             try
827             {
828                 nIdPurchase = Integer.parseInt( strPurchaseId );
829             }
830             catch( NumberFormatException e )
831             {
832                 LOGGER.debug( e );
833 
834                 return AdminMessageService.getMessageUrl( request, StockConstants.MESSAGE_ERROR_OCCUR, AdminMessage.TYPE_STOP );
835             }
836 
837             _servicePurchase.doDeletePurchase( nIdPurchase );
838         }
839         else
840         {
841             for ( Object parameter : request.getParameterMap( ).keySet( ) )
842             {
843                 if ( parameter instanceof String )
844                 {
845                     if ( ( (String) parameter ).startsWith( MARK_PURCHASSE_ID ) )
846                     {
847                         try
848                         {
849                             nIdPurchase = Integer.parseInt( request.getParameter( (String) parameter ) );
850                         }
851                         catch( NumberFormatException e )
852                         {
853                             LOGGER.debug( e );
854 
855                             return AdminMessageService.getMessageUrl( request, StockConstants.MESSAGE_ERROR_OCCUR, AdminMessage.TYPE_STOP );
856                         }
857 
858                         _servicePurchase.doDeletePurchase( nIdPurchase );
859                     }
860                 }
861             }
862         }
863 
864         return doGoBack( request );
865     }
866 
867     /**
868      * Returns the confirmation message to notify purchaser
869      *
870      * @param request
871      *            The Http request
872      * @return the html code message
873      */
874     public String getNotifyPurchase( HttpServletRequest request )
875     {
876         String strPurchaseId = request.getParameter( PARAMETER_PURCHASE_ID );
877 
878         Integer nIdPurchase;
879 
880         try
881         {
882             nIdPurchase = Integer.parseInt( strPurchaseId );
883         }
884         catch( NumberFormatException e )
885         {
886             LOGGER.debug( e );
887 
888             return AdminMessageService.getMessageUrl( request, StockConstants.MESSAGE_ERROR_OCCUR, AdminMessage.TYPE_STOP );
889         }
890 
891         ReservationDTO purchase = _servicePurchase.findById( nIdPurchase );
892 
893         Object [ ] args = new Object [ ] {
894                 purchase.getEmailAgent( ), purchase.getOffer( ).getProduct( ).getName( ), purchase.getOffer( ).getDate( ), purchase.getOffer( ).getHour( ),
895                 purchase.getOffer( ).getTypeName( ), purchase.getQuantity( ),
896         };
897 
898         Map<String, Object> urlParam = new HashMap<String, Object>( );
899         urlParam.put( PARAMETER_PURCHASE_ID, nIdPurchase );
900 
901         String strJspBack = JSP_MANAGE_PURCHASES;
902 
903         return AdminMessageService.getMessageUrl( request, MESSAGE_NOTIFY_PURCHASE_CONFIRMATION, args, MESSAGE_TITLE_NOTIFY_PURCHASE_CONFIRMATION,
904                 JSP_DO_NOTIFY_PURCHASE, BilletterieConstants.TARGET_SELF, AdminMessage.TYPE_CONFIRMATION, urlParam, strJspBack );
905     }
906 
907     /**
908      * Send booking notification.
909      *
910      * @param request
911      *            The Http request
912      * @return the html code message
913      */
914     public String doNotifyPurchase( HttpServletRequest request )
915     {
916         String strPurchaseId = request.getParameter( PARAMETER_PURCHASE_ID );
917 
918         Integer nIdPurchase;
919 
920         try
921         {
922             nIdPurchase = Integer.parseInt( strPurchaseId );
923         }
924         catch( NumberFormatException e )
925         {
926             LOGGER.debug( e );
927 
928             return AdminMessageService.getMessageUrl( request, StockConstants.MESSAGE_ERROR_OCCUR, AdminMessage.TYPE_STOP );
929         }
930 
931         ReservationDTO purchase = _servicePurchase.findById( nIdPurchase );
932 
933         // Generate mail content
934         Map<String, Object> model = new HashMap<String, Object>( );
935         model.put( MARK_PURCHASE, purchase );
936         model.put( MARK_BASE_URL, AppPathService.getBaseUrl( request ) );
937 
938         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_NOTIFICATION_BOOKING, request.getLocale( ), model );
939 
940         // Create mail object
941         NotificationDTO notificationDTO = new NotificationDTO( );
942         notificationDTO.setRecipientsTo( purchase.getEmailAgent( ) );
943 
944         String [ ] args = new String [ ] {
945             purchase.getOffer( ).getName( ),
946         };
947         notificationDTO.setSubject( I18nService.getLocalizedString( MESSAGE_NOTIFICATION_BOOKING_SUBJECT, args, request.getLocale( ) ) );
948         notificationDTO.setMessage( template.getHtml( ) );
949 
950         // Send it
951         _serviceNotification.send( notificationDTO );
952 
953         return doGoBack( request );
954     }
955 
956     /**
957      * Returns the confirmation message to delete purchases
958      *
959      * @param request
960      *            The Http request
961      * @return the html code message
962      */
963     public String getMasseDeletePurchase( HttpServletRequest request )
964     {
965         String [ ] parameterValues = request.getParameterValues( PARAMETER_PURCHASES_ID );
966 
967         // if no case checked
968         if ( parameterValues == null )
969         {
970             return AdminMessageService.getMessageUrl( request, MESSAGE_DELETE_MASSE_PURCHASE_NO_CHECK, AdminMessage.TYPE_STOP );
971         }
972 
973         Map<String, Object> urlParam = new HashMap<String, Object>( );
974 
975         try
976         {
977             for ( String id : parameterValues )
978             {
979                 urlParam.put( MARK_PURCHASSE_ID + Integer.parseInt( id ), Integer.parseInt( id ) );
980             }
981         }
982         catch( NumberFormatException e )
983         {
984             LOGGER.debug( e );
985 
986             return AdminMessageService.getMessageUrl( request, StockConstants.MESSAGE_ERROR_OCCUR, AdminMessage.TYPE_STOP );
987         }
988 
989         boolean masse = urlParam.size( ) > 1;
990 
991         String strJspBack = JSP_MANAGE_OFFERS;
992 
993         return AdminMessageService.getMessageUrl( request, masse ? MESSAGE_CONFIRMATION_MASSE_DELETE_PURCHASE : MESSAGE_CONFIRMATION_DELETE_PURCHASE, null,
994                 MESSAGE_TITLE_CONFIRMATION_DELETE_PURCHASE, JSP_DO_DELETE_PURCHASE, BilletterieConstants.TARGET_SELF, AdminMessage.TYPE_CONFIRMATION, urlParam,
995                 strJspBack );
996     }
997 }