View Javadoc

1   package org.paneris.jammyjoes.shopping;
2   
3   import java.io.PrintWriter;
4   import java.io.StringWriter;
5   import java.util.Enumeration;
6   import java.util.Locale;
7   
8   import org.melati.Melati;
9   import org.melati.servlet.Form;
10  import org.melati.login.HttpSessionAccessHandler;
11  import org.melati.poem.AccessPoemException;
12  import org.melati.poem.AccessToken;
13  import org.melati.poem.Field;
14  import org.melati.poem.PoemTask;
15  import org.melati.poem.PoemThread;
16  import org.melati.template.ServletTemplateContext;
17  import org.melati.util.InstantiationPropertyException;
18  import org.paneris.jammyjoes.model.Affiliate;
19  import org.paneris.jammyjoes.model.DeliveryCarrier;
20  import org.paneris.jammyjoes.model.DeliveryCharge;
21  import org.paneris.jammyjoes.model.DeliveryZone;
22  import org.paneris.jammyjoes.model.JammyjoesDatabase;
23  import org.paneris.jammyjoes.model.OrderType;
24  import org.paneris.jammyjoes.model.ShopCurrency;
25  import org.paneris.jammyjoes.model.ShopOrder;
26  import org.paneris.jammyjoes.model.ShopOrderItem;
27  import org.paneris.jammyjoes.model.User;
28  import org.paneris.jammyjoes.model.UserTable;
29  import org.paneris.jammyjoes.model.Wrapping;
30  import org.paneris.jammyjoes.model.WrappingTable;
31  import org.paneris.jammyjoes.util.JammyJoesContextUtil;
32  import org.paneris.jammyjoes.util.JammyJoesUtil;
33  
34  /**
35  * <p> A Shopping Trolley stored information in the user's Shopping Trolley.<p>
36  * <p> It does this by storing itself in the session.</p>
37  * <p> For this reason, the constructors are private, and you will be expected to
38  * always get the Shopping Trolley using getInstance();</p>
39  *
40  * usage example:
41  *
42  * ShoppingTrolley trolley = ShoppingTrolley.getInstance(Melati melati);
43  * context.put("trolley", trolley);
44  *
45  **/
46  
47  public class JammyJoesShoppingTrolley extends ShoppingTrolley {
48  
49    public DeliveryZone zone;
50    public Wrapping wrapping;
51    private ShopOrder order = null;
52    public DeliveryCarrier carrier;
53    private Boolean spam;
54    private String comment;
55    private String deliveryName;
56  
57   /**
58    *  Get the Locale for this trolley.
59    */
60    public Locale getLocale() {
61      // attempt to get from user preferences
62      if (locale == null) {
63        //JammyjoesDatabase db = (JammyjoesDatabase) melati.getDatabase();
64        User user = (User) melati.getUser();
65        if (!user.isGuest() && user.getCurrency() != null) {
66          locale = user.getCurrency().toLocale();
67        }
68        // attempt to find from user's http headers
69        if (locale == null) {
70          locale = JammyJoesUtil.makeLocale(melati.getRequest().getHeader("accept-language"));
71        }
72      }
73      return locale;
74    }
75  
76    private boolean isOrderPaidOrNew() {
77      JammyjoesDatabase db = (JammyjoesDatabase) melati.getDatabase();
78      if (order == null) {
79        return true;
80      }
81      if (order.getStatus() == db.getOrderStatusTable().getPaid()) {
82        return true;
83      }
84      return false;
85    }
86  
87    /* load a trolley from something persistent
88    */
89    public void load(Integer id) throws InstantiationPropertyException {
90      JammyjoesDatabase db = (JammyjoesDatabase) melati.getDatabase();
91      order = db.getShopOrderTable().getShopOrderObject(id);
92      setZone(order.getZone());
93      setWrapping(order.getWrapping());
94      setName(order.getName());
95      setEmail(order.getEmail());
96      setTel(order.getTel());
97      setDeliveryAddress(order.getAddress());
98      setTown(order.getTown());
99      setPostcode(order.getPostcode());
100     setMessage(order.getMessage());
101     comment = order.getCustomerComment();
102     deliveryName = order.getDeliveryName();
103     setCountry(order.getCountry());
104     setLocale(order.getCurrency().toLocale());
105     setSpam(order.getSpam());
106     Enumeration e = order.getItems();
107     while (e.hasMoreElements()) {
108       ShopOrderItem line = (ShopOrderItem) e.nextElement();
109       ShoppingTrolleyItem item = newItem(line.getProduct().getTroid(), null, null);
110       if (line.getQuantity() != null) {
111         item.setQuantity(line.getQuantity());
112       }
113     }
114   }
115 
116   /* save a trolley to something persistent
117   */
118   public void save() {
119     if (JammyJoesUtil.telesales(melati)) {
120       saveCatalogueOrder();
121       return;
122     }
123     final JammyjoesDatabase db = (JammyjoesDatabase) melati.getDatabase();
124     User user = (User) melati.getUser();
125     if (user.isGuest()) {
126       user = null;
127     }
128     user = saveOrder(db, null, db.getOrderTypeTable().getOnlineOrder());
129     melati.getSession().setAttribute(HttpSessionAccessHandler.USER, user);
130   }
131 
132 //in this flow, the user is actually the phone operator  
133   public void saveCatalogueOrder() {
134     final JammyjoesDatabase db = (JammyjoesDatabase) melati.getDatabase();
135     User operator = (User) melati.getUser();
136     if (operator == null || operator.isGuest()) {
137       throw new AccessPoemException();
138     }
139     saveOrder(db, null, db.getOrderTypeTable().getTelephoneOrder());
140     order.setOperator(operator);
141   }
142 
143   private User saveOrder(final JammyjoesDatabase db, User user, OrderType type) {
144     if (user == null) {
145       user = (User) ((UserTable) db.getUserTable()).getEmailColumn().firstWhereEq(email);
146       if (user == null) {
147       // we have new user, save their details for next time
148       final User newUser;
149       newUser = (User) db.getUserTable().newPersistent();
150       newUser.setName(name);
151       newUser.setEmail(email);
152       newUser.setTel(tel);
153       newUser.setAddress(address);
154       newUser.setTown(town);
155       newUser.setZone(zone);
156       newUser.setCountry(country);
157       newUser.setPostcode(postcode);
158       newUser.setSpam(spam);
159       newUser.generateDefaults();
160       PoemThread.withAccessToken(AccessToken.root, new PoemTask() {
161           public void run() {
162             db.getUserTable().create(newUser);
163           }
164         });
165         user = newUser;
166       }
167     } else {
168       // we have a genuinely logged in user, save their details for next time
169       user.setName(name);
170       user.setEmail(email);
171       user.setTel(tel);
172       user.setAddress(address);
173       user.setTown(town);
174       user.setZone(zone);
175       user.setPostcode(postcode);
176       user.setCountry(country);
177       user.setZone(zone);
178       user.setSpam(spam);
179     }
180     if (isOrderPaidOrNew()) {
181       order = (ShopOrder) db.getShopOrderTable().newPersistent();
182       order.setType(type);
183     } else {
184       order.removeItems();
185     }
186     order.setUser(user);
187     order.setName(name);
188     order.setEmail(email);
189     order.setTel(tel);
190     order.setAddress(address);
191     order.setTown(town);
192     order.setZone(zone);
193     order.setWrapping(wrapping);
194     order.setPostcode(postcode);
195     order.setCountry(country);
196     order.setMessage(message);
197     order.setCustomerComment(comment);
198     order.setDeliveryName(deliveryName);
199     order.setStatus(db.getOrderStatusTable().getIncomplete());
200     order.setAmount(convertFromUK(getTotalValue()));
201     order.setDelivery(convertFromUK(getTotalDeliveryValue()));
202     order.setAmountUK(JammyJoesUtil.roundTo2dp(getTotalValue()));
203     order.setDeliveryUK(JammyJoesUtil.roundTo2dp(getTotalDeliveryValue()));
204     order.setCurrency(getCurrency());
205     order.setAffiliatepaid(false);
206     order.setAlert(false);
207     order.setComission(0d);
208     order.setSpam(spam);
209     String affiliateId = JammyJoesUtil.getCookieValue(melati, "jammyjoes");
210     if (affiliateId != null) {
211       Affiliate affiliate = (Affiliate)db.getAffiliateTable().getObject(new Integer(affiliateId));
212       order.setAffiliate(affiliate);
213       order.setComission(affiliate.getPercentage());
214     }
215     if (order.getTroid() == null) {
216       db.getShopOrderTable().create(order);
217     }
218     for (Enumeration en = getItems(); en.hasMoreElements();) {
219       JammyJoesShoppingTrolleyItem item = (JammyJoesShoppingTrolleyItem) en.nextElement();
220       item.save(db, order);
221     }
222     return user;
223   }
224 
225   /* provide a mechanism for working out if
226      this order should include a delivery charge
227   */
228   public boolean hasDelivery() {
229     if (zone == null)
230       return false;
231     return true;
232   }
233 
234   public boolean allInStock() {
235     boolean inStock = true;
236     for (Enumeration en = getItems(); en.hasMoreElements();) {
237       JammyJoesShoppingTrolleyItem item = (JammyJoesShoppingTrolleyItem) en.nextElement();
238       if (!item.enoughStock())
239         inStock = false;
240     }
241     return inStock;
242   }
243 
244   public boolean hasWrapping() {
245     if (wrapping == null)
246       return false;
247     WrappingTable wrappingTable = ((JammyjoesDatabase) melati.getDatabase()).getWrappingTable();
248     if (wrapping.equals(wrappingTable.getNoWrapping()))
249       return false;
250     return true;
251   }
252 
253   public DeliveryZone getDeliveryZone() {
254     return zone;
255   }
256 
257   public Wrapping getWrapping() {
258     return wrapping;
259   }
260 
261   public DeliveryCarrier getDeliveryCarrier() {
262     return carrier;
263   }
264 
265   public Field getZones() {
266     JammyjoesDatabase db = (JammyjoesDatabase) melati.getDatabase();
267     Integer current = null;
268     if (zone != null)
269       current = zone.getTroid();
270     return new Field(current, db.getDeliveryChargeTable().getZoneColumn());
271   }
272 
273   public Field getWrappings() {
274     JammyjoesDatabase db = (JammyjoesDatabase) melati.getDatabase();
275     Integer current = null;
276     if (wrapping != null)
277       current = wrapping.getTroid();
278     return new Field(current, db.getShopOrderTable().getWrappingColumn());
279   }
280 
281   public void setFromForm(Melati melati) {
282     ServletTemplateContext tc = melati.getServletTemplateContext();
283     setName(Form.getFormNulled(tc, "trolley_name"));
284     setEmail(Form.getFormNulled(tc, "trolley_email"));
285     setTel(Form.getFormNulled(tc, "trolley_tel"));
286     setDeliveryAddress(Form.getFormNulled(tc, "trolley_deliveryaddress"));
287     setTown(Form.getFormNulled(tc, "trolley_town"));
288     setCounty(Form.getFormNulled(tc, "trolley_county"));
289     setCountry(Form.getFormNulled(tc, "trolley_country"));
290     setPostcode(Form.getFormNulled(tc, "trolley_postcode"));
291     setMessage(Form.getFormNulled(tc, "trolley_message"));
292     hasDetails = true;
293 
294     JammyjoesDatabase db = (JammyjoesDatabase) melati.getDatabase();
295     Integer zoneId = Form.getIntegerField(tc, "field_zone");
296     DeliveryZone newCode = (DeliveryZone) db.getDeliveryZoneTable().getObject(zoneId);
297     setZone(newCode);
298     Integer wrappingId = Form.getIntegerField(tc, "field_wrapping");
299     WrappingTable wrappingTable = db.getWrappingTable();
300     Wrapping newWrapping = (Wrapping) wrappingTable.getObject(wrappingId);
301     setWrapping(newWrapping);
302     setSpam(Form.getBooleanField(tc, "trolley_spam"));
303     comment = Form.getFormNulled(tc, "trolley_comment");
304     deliveryName = Form.getFormNulled(tc, "trolley_deliveryName");
305   }
306 
307   /* you need to provide some mechanism for calculating the delivery
308      value for the order (item delivery values are calculated individually
309   */
310   public double getDeliveryValue() {
311     carrier = null;
312     if (zone == null)
313       return 0;
314     double cost = 0;
315     //    if (wrapping != null) cost += 2;
316     if (zone.getChargeByValue() != null && zone.getChargeByValue().booleanValue()) {
317       cost += getDeliveryValueByValue();
318     } else {
319       cost += getDeliveryValueByWeight();
320     }
321     return cost;
322   }
323   public double getWrappingValue() {
324     if (hasWrapping())
325       return WrappingTable.WRAPPING_COST;
326     return 0;
327   }
328 
329   public double getDeliveryValueByValue() {
330     carrier = null;
331     if (zone == null)
332       return 0;
333     DeliveryCharge thisCharge = zone.getChargeValue(getValue());
334     if (thisCharge == null)
335       return 0;
336     carrier = thisCharge.getCarrier();
337     return thisCharge.getCost().doubleValue();
338   }
339 
340   public double getDeliveryValueByWeight() {
341     carrier = null;
342     if (zone == null)
343       return 0;
344     DeliveryCharge maxCharge = zone.getMaxCharge();
345     if (maxCharge == null)
346       return 0;
347     double weight = getTotalWeight();
348     double cost = 0;
349     while (weight > maxCharge.getWeight().doubleValue()) {
350       cost += maxCharge.getCost().doubleValue();
351       weight -= maxCharge.getWeight().doubleValue();
352     }
353     DeliveryCharge thisCharge = zone.getCharge(weight);
354     if (thisCharge == null)
355       return cost;
356     cost += thisCharge.getCost().doubleValue();
357     carrier = thisCharge.getCarrier();
358     return cost;
359   }
360 
361   public double getTotalWeight() {
362     double weight = 0;
363     for (Enumeration en = getItems(); en.hasMoreElements();) {
364       JammyJoesShoppingTrolleyItem item = (JammyJoesShoppingTrolleyItem) en.nextElement();
365       weight += item.getWeight();
366     }
367     return weight;
368   }
369 
370   /* provide a mechanism for working out if
371      this order should include a discount
372   */
373   public boolean hasDiscount() {
374     return false;
375   }
376 
377   /* if you want to apply a discount to this order, do it here
378   */
379   public double getDiscountRate() {
380     return 0;
381   }
382 
383   /* provide a mechanism for working out if
384      this order should include VAT (default should be true)
385   */
386   public boolean hasVAT() {
387     return true;
388   }
389 
390   /* set the user's detault details into this trolley.  this is useful
391    * if users have already logged in, and we don't want them to reenter their
392    * details
393    */
394   public void setDefaultDetails(Melati melati) {
395     if (!JammyJoesUtil.telesales(melati)) {
396     User user = (User) melati.getUser();
397     if (user != null && !user.isGuest()) {
398       if (address == null)
399         address = user.getAddress();
400       if (town == null)
401         town = user.getTown();
402       if (zone == null)
403         zone = user.getZone();
404       if (name == null)
405         name = user.getName();
406       if (tel == null)
407         tel = user.getTel();
408       if (country == null)
409         country = user.getCountry();
410       if (postcode == null)
411         postcode = user.getPostcode();
412       if (email == null)
413         email = user.getEmail();
414       if (spam == null)
415         setSpam(user.getSpam());
416     }
417     }
418   }
419 
420   public void confirmPayment(Melati melati) {
421     JammyjoesDatabase db = (JammyjoesDatabase) melati.getDatabase();
422     ServletTemplateContext context = melati.getServletTemplateContext();
423     String amountString = context.getForm("amount");
424     amountString = amountString.trim();
425     String uniqueString = melati.getRequest().getQueryString();
426     Integer orderInteger = Form.getIntegerField(context, "orderref");
427     boolean error = false;
428     try {
429       Integer amount = new Integer(amountString);
430       load(orderInteger);
431       context.put("trolley", this);
432       context.put("jjutil", new JammyJoesContextUtil());
433       if (!uniqueString.equals("few90kjnr32908908kjfdsa98432kjlfds9009432lk90lk43209")) {
434         error = true;
435         context.put("error", "2");
436       }
437       if (!amount.equals(new Integer(getTotalValuePence()))) {
438         error = true;
439         context.put("expect", getTotalValuePence());
440         context.put("paid", amountString);
441         context.put("error", "1");
442       }
443       if (!error) {
444         order.setStatus(db.getOrderStatusTable().getPaid());
445         for (Enumeration en = order.getItems(); en.hasMoreElements();) {
446           ShopOrderItem item = (ShopOrderItem) en.nextElement();
447           item.setTransaction();
448         }
449         remove(melati);
450       }
451     } catch (Exception e) {
452       error = true;
453       StringWriter sw = new StringWriter();
454       PrintWriter pw = new PrintWriter(sw);
455       e.printStackTrace(pw);
456       context.put("error", sw);
457     }
458   }
459 
460   /**
461    * remove any trolley from the session
462    */
463   public void remove(Melati melati) {
464     super.remove(melati);
465     melati.getSession().removeAttribute(HttpSessionAccessHandler.USER);
466   }
467 
468   public ShopOrder getOrder() {
469     return order;
470   }
471 
472   /* calculate the total value of this order
473   */
474   public double getTotalValue() {
475     return getValue()
476       + getTotalDeliveryValue()
477       + getDiscountValue()
478       + getWrappingValue()
479       + getVATValue();
480   }
481 
482   /* calculate the amount of vat on this order
483   */
484   public double getTotalVat() {
485     return roundTo2dp(getTotalValue() / 1.175 * 0.175);
486   }
487 
488   public String getWrappingDisplay() {
489     return displayCurrency(getWrappingValue());
490   }
491 
492   /* format a number in the locale currency
493   */
494   public String convertFromUKandFormat(double value) {
495     return getCurrency().convertFromUKandFormat(value);
496   }
497   /* convert from foreign currency back to sterling
498   */
499   public double convertFromUK(double value) {
500     return getCurrency().convertFromUK(value);
501   }
502 
503   /* convert from foreign currency back to sterling
504   */
505   public double convertToUK(double value) {
506     return getCurrency().convertToUK(value);
507   }
508 
509   public ShopCurrency getCurrency(Locale locale) {
510     return ((JammyjoesDatabase) melati.getDatabase()).getShopCurrencyTable().getCurrency(locale);
511   }
512 
513   public ShopCurrency getCurrency() {
514     return getCurrency(getLocale());
515   }
516 
517   public String displayCurrency(double value) {
518     return convertFromUKandFormat(value);
519   }
520 
521   public void setWrapping(Wrapping newWrapping) {
522     wrapping = newWrapping;
523   }
524 
525   public void setZone(DeliveryZone zone) {
526     this.zone = zone;
527   }
528 
529   public void setSpam(Boolean s) {
530     spam = s;
531   }
532 
533   public String getComment() {
534     return comment;
535   }
536 
537   public String getDeliveryName() {
538     return deliveryName;
539   }
540 
541   public Boolean getSpam() {
542     if (spam == null)
543       return Boolean.TRUE;
544     return spam;
545   }
546 
547   private JammyJoesContextUtil jjutil;
548   public JammyJoesContextUtil getJJUtil() {
549     if (jjutil == null)
550       jjutil = new JammyJoesContextUtil();
551     return jjutil;
552   }
553 
554 }