Package uk.org.woodcraft.bookings

Source Code of uk.org.woodcraft.bookings.ApplyCoCampDiscountsAction$DiscountLine

package uk.org.woodcraft.bookings;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;

import uk.org.woodcraft.bookings.auth.SecurityModel;
import uk.org.woodcraft.bookings.datamodel.Booking;
import uk.org.woodcraft.bookings.datamodel.Event;
import uk.org.woodcraft.bookings.datamodel.Predicates;
import uk.org.woodcraft.bookings.datamodel.Transaction;
import uk.org.woodcraft.bookings.datamodel.TransactionType;
import uk.org.woodcraft.bookings.datamodel.Unit;
import uk.org.woodcraft.bookings.persistence.CannedQueries;
import uk.org.woodcraft.bookings.persistence.SessionBasedAction;
import uk.org.woodcraft.bookings.utils.Clock;
import uk.org.woodcraft.bookings.utils.DateUtils;

import com.google.appengine.api.datastore.Key;

public class ApplyCoCampDiscountsAction extends SessionBasedAction {

  private static final long serialVersionUID = 4164806583384446180L;

  public static final String SESSION_DISCOUNT_LIST = "DISCOUNT_LIST";
  private static final double DISCOUNT_AMOUNT = 10.0d;
 
  private static final Predicate SELECT_DISCOUNT = new Predicates.TransactionTypePredicate(TransactionType.Discount);
 
  private List<DiscountLine> discountLines = new ArrayList<DiscountLine>();
  private double totalDiscount;
 
  public String generateDiscounts() {
    SecurityModel.checkIsAdminUser(this);
    Event event = getCurrentEvent();
   
    Map<Unit, List<Transaction>> transactionsByUnit = getRelevantTransactions(event);
    Map<Key, List<Booking>> bookingsByUnit = getRelevantBookings(event);
   
    List<Transaction> allDiscounts = new ArrayList<Transaction>();
    totalDiscount = 0;
    for(Unit unit : transactionsByUnit.keySet())
    {
      List<Booking> bookingsForUnit = bookingsByUnit.get(unit.getKeyCheckNotNull());
      if (bookingsForUnit == null) bookingsForUnit = new ArrayList<Booking>();
      DiscountLine unitDiscount = new DiscountLine(getClock(), event, unit, bookingsForUnit, transactionsByUnit.get(unit), DISCOUNT_AMOUNT);
      getDiscountLines().add(unitDiscount);
     
      // Only persist the discount if it is non-zero
      if (unitDiscount.getDiscount().getAmount() != 0)
        allDiscounts.add(unitDiscount.getDiscount());
      totalDiscount += unitDiscount.getDiscount().getAmount();
    }
   
    // Cache it so that we can apply these discounts if approved
    setSessionObject(SESSION_DISCOUNT_LIST, (Serializable) allDiscounts);
   
    return SUCCESS;
  }
 
 
  public String confirmDiscounts() {
    SecurityModel.checkIsAdminUser(this);
    @SuppressWarnings("unchecked")
    List<Transaction> discountsToApply = (List<Transaction>)getSessionObject(SESSION_DISCOUNT_LIST);
   
    if (discountsToApply == null)
    {
      addActionError("Unable to find the set of discounts to add! Failed to set new discounts");
      return ERROR;
    }
   
    // This really needs to be atomic, but hey ho.
   
    // First purge existing discounts for this event
    @SuppressWarnings("unchecked")
    Collection<Transaction> discounts = CollectionUtils.select(CannedQueries.transactionsForEvent(getCurrentEvent()), SELECT_DISCOUNT);
   
    // Can't delete all in one transaction as seperate entity groups
    for(Transaction discount : discounts)
      CannedQueries.delete(discount);
   
    CannedQueries.save(discountsToApply);
    addActionMessage(String.format("Successfully added %d discounts", discountsToApply.size()));
   
    return SUCCESS;
  }
 
  public Map<Unit, List<Transaction>> getRelevantTransactions(Event event)
  {
    Map<Unit, List<Transaction>> relevantTransactions = new HashMap<Unit, List<Transaction>>();
   
    Date eventEarlyBookingDeadline = DateUtils.cleanupTime(event.getEarlyBookingDeadline());
   
    for(Transaction transaction : CannedQueries.transactionsForEvent(event))
    {
      if (!DateUtils.cleanupTime(transaction.getTimestamp()).after(eventEarlyBookingDeadline) || transaction.getType() == TransactionType.Discount)
      {
        // Ignore any additional bills
        if ( !transaction.getType().getIsCost())
        {
          Unit unit = transaction.getUnit();
          List<Transaction> transactionsForUnit = relevantTransactions.get(unit);
         
          if (transactionsForUnit == null )
          {
            transactionsForUnit = new ArrayList<Transaction>();
            relevantTransactions.put(unit, transactionsForUnit);
         
         
          transactionsForUnit.add(transaction);
        }
      }
    }
    return relevantTransactions;
  }
 
  public Map<Key,List<Booking>> getRelevantBookings(Event event)
  {
    Map<Key, List<Booking>> relevantBookings = new HashMap<Key, List<Booking>>();
   
    Date eventEarlyBookingDeadline = DateUtils.cleanupTime(event.getEarlyBookingDeadline());
    for(Booking booking : CannedQueries.bookingsForEvent(event))
    {
      if (!DateUtils.cleanupTime(booking.getBookingCreationDate()).after(eventEarlyBookingDeadline))
      {
        // Only full price bookings apply
        if (booking.getFee() == 150d)
        {
          Key unitKey = booking.getUnitKey();
          List<Booking> bookingsForUnit = relevantBookings.get(unitKey);
          if (bookingsForUnit == null)
          {
            bookingsForUnit = new ArrayList<Booking>();
            relevantBookings.put(unitKey, bookingsForUnit);
          }
         
          bookingsForUnit.add(booking);
        }
      }
    }
    return relevantBookings;   
  }


  public List<DiscountLine> getDiscountLines() {
    return discountLines;
  }

  public double getTotalDiscount() {
    return totalDiscount;
  }

  public static class DiscountLine implements Serializable
  {
    private static final long serialVersionUID = -7084864059096169005L;
 
    private Unit unit;
    private Collection<Booking> paidBookings = new ArrayList<Booking>();
    private Collection<Booking> unpaidBookings = new ArrayList<Booking>();
    private Collection<Transaction> qualifyingPayments;

    private Transaction previousDiscount;
    private Transaction discount;
   
    public DiscountLine(Clock clock, Event event, Unit unit, List<Booking> qualifyingBookings,
                 List<Transaction> qualifyingTransactions,
                 double rebateAmountPerBooking)
    {
      this.unit = unit;
     
      @SuppressWarnings("unchecked")
      Collection<Transaction> qualifyingPayments = CollectionUtils.selectRejected(qualifyingTransactions, SELECT_DISCOUNT);
           
      this.previousDiscount = (Transaction) CollectionUtils.find(qualifyingTransactions, SELECT_DISCOUNT);
      calculateDiscount(clock.getTime(), event, qualifyingBookings, qualifyingPayments, rebateAmountPerBooking);
    }
   
    private void calculateDiscount( Date timestamp, Event event, Collection<Booking> qualifyingBookings, Collection<Transaction> qualifyingPayments, double rebateAmount)
    {
      this.qualifyingPayments = qualifyingPayments;
      double qualifyingPaymentTotal = getTotalQualifyingPayments();
      double balance = qualifyingPaymentTotal;
     
      // iterate the bookings until we have no money left
      for(Booking booking : qualifyingBookings)
      {
        if (balance >= booking.getFee() / 2)
        {
          balance -= (booking.getFee() / 2);
          paidBookings.add(booking);
        } else {
          unpaidBookings.add(booking);
        }
      }
   
      int numberOfDiscountBookings = paidBookings.size();
      double amountToDiscount = numberOfDiscountBookings * rebateAmount;
      String discountName = String.format("Earlybird booking discount for %d people", numberOfDiscountBookings);
      String discountComment = String.format("%.2f received prior to deadline", qualifyingPaymentTotal);
      if (unpaidBookings.size() > 0)
        discountComment += String.format("; There were %d additional bookings with insufficient funds received to qualify for the discount",
                    unpaidBookings.size());
     
      discount = new Transaction(unit.getKeyCheckNotNull(), event.getKeyCheckNotNull(),
          timestamp, TransactionType.Discount, discountName, discountComment, amountToDiscount);
     
    }
   
    public double getTotalQualifyingPrice()
    {
      double total = 0;
      for(Booking booking : paidBookings)
        total += booking.getFee()/2;
      return total;
    }
   
    public double getTotalQualifyingPayments()
    {
      double total = 0;
      for(Transaction transaction : qualifyingPayments)
        total += transaction.getAmount();
      return total;
    }

    public Unit getUnit() {
      return unit;
    }


    public Collection<Booking> getPaidBookings() {
      return paidBookings;
    }
   
    public Collection<Booking> getUnpaidBookings() {
      return unpaidBookings;
    }
   
    public Collection<Transaction> getQualifyingPayments() {
      return qualifyingPayments;
    }

    public Transaction getPreviousDiscount() {
      return previousDiscount;
    }
   
    public Transaction getDiscount() {
      return discount;
   
   
    @Override
    public String toString() {
      return String.format("%s - %.2f discount, %.2f paid, %d bookings covered, %d bookings outstanding, %s",
            unit.getName(), discount.getAmount(), getTotalQualifyingPayments(), paidBookings.size(), unpaidBookings.size(), discount.getName());
    }
  }
}
TOP

Related Classes of uk.org.woodcraft.bookings.ApplyCoCampDiscountsAction$DiscountLine

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.