BrightSide Workbench Full Report + Source Code
Checkout.java
Go to the documentation of this file.
1 /*
2  * Turró i Cutiller Foundation. License notice.
3  * Copyright (C) 2016 Lluis Turró Cutiller <http://www.turro.org/>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Affero General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Affero General Public License for more details.
14  *
15  * You should have received a copy of the GNU Affero General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 package org.turro.financials.cart.www;
20 
21 import java.io.File;
22 import java.io.FileOutputStream;
23 import java.io.IOException;
24 import java.util.Collection;
25 import java.util.Currency;
26 import java.util.logging.Level;
27 import java.util.logging.Logger;
28 import org.turro.string.Strings;
29 import org.apache.commons.lang3.LocaleUtils;
30 import org.apache.commons.mail.EmailException;
31 import org.turro.action.Contacts;
32 import org.turro.action.MailAttachment;
33 import org.turro.action.MailSenders;
34 import org.turro.attach.search.AttachCollection;
35 import org.turro.auth.Authentication;
36 import org.turro.contacts.Address;
37 import org.turro.contacts.Contact;
38 import org.turro.contacts.form.ContactWrapper;
39 import org.turro.elephant.context.ElephantContext;
40 import org.turro.elephant.context.IConstructor;
41 import org.turro.elephant.impl.util.StringParser;
42 import org.turro.elephant.security.IUser;
43 import org.turro.financials.cart.Cart;
44 import org.turro.financials.cart.CartItem;
45 import org.turro.financials.cart.RedsysPOS;
46 import org.turro.financials.cart.ShopContext;
47 import org.turro.financials.cart.ShoppingCart;
48 import org.turro.financials.cart.delivery.DeliveryContexts;
49 import org.turro.financials.db.FinancialsPU;
50 import org.turro.financials.entity.Document;
51 import org.turro.financials.entity.DocumentLine;
52 import org.turro.financials.entity.Product;
53 import org.turro.financials.model.document.GenerateDocument;
54 import org.turro.jpa.Dao;
55 import org.turro.log.SystemLogType;
56 import org.turro.log.SystemLogger;
57 import org.turro.marker.ElephantMarker;
58 import org.turro.plugin.contacts.IContact;
59 import org.turro.util.PhraseBuilder;
60 
65 public class Checkout {
66 
67  private final IConstructor constructor;
68  private final IContact contact;
69  private final Cart cart;
70 
71  public Checkout(IConstructor constructor) {
72  this.constructor = constructor;
73  contact = Authentication.getIContact();
74  cart = ShoppingCart.getCart(constructor);
75  checkCheckout();
76  }
77 
78  public void renderCheckout() {
79  ElephantMarker marker = new ElephantMarker(constructor);
80  marker.put("contact", contact);
81  marker.put("checkout", this);
82  marker.put("cart", cart);
83  switch(cart.getStatus()) {
84  case 0: // nothing
85  marker.process("cart", "none");
86  break;
87  case 1: // cart
88  cart.removeDeliveryItem();
89  marker.process("cart", "confirm");
90  break;
91  case 2: // address, document
92  marker.put("address", getAddress(ShopContext.getInstance().getDelivery()));
93  marker.put("mobile", contact.getConnector(ShopContext.getInstance().getContactPhone()));
94  marker.put("pickup", cart.isPickup());
95  marker.process("cart", "delivery");
96  break;
97  case 3: // billing address, gid
98  marker.put("address", getAddress(ShopContext.getInstance().getFiscal()));
99  marker.process("cart", "billing");
100  break;
101  case 4: // needs delivery
102  if(cart.needsDelivery() && !cart.isPickup()) {
103  cart.removeDeliveryItem();
104  Address delivery = getAddress(ShopContext.getInstance().getDelivery());
105  if(delivery != null && !delivery.isEmpty()) {
107  Product product = dcs.getDeliveryProduct(delivery);
108  if(product != null) {
109  cart.addDeliveryItem(product.getId(), 1, product.getTax(), product.getPrice());
110  } else if(!Strings.isBlank(cart.getDeliveryValue())) {
111  product = dcs.getDeliveryProduct(cart.getDeliveryValue());
112  if(product != null) {
113  cart.addDeliveryItem(product.getId(), 1, product.getTax(), product.getPrice());
114  }
115  }
116  if(product == null) {
117  cart.setStatus(2);
118  marker.process("cart", "outofscope");
119  break;
120  }
121  }
122  marker.put("address", delivery);
123  }
124  marker.put("fiscal", getAddress(ShopContext.getInstance().getFiscal()));
125  marker.put("mobile", contact.getConnector(ShopContext.getInstance().getContactPhone()));
127  cart.getResetOrder();
128  cart.serializeForOrder(contact);
129  marker.put("notificationURL", ElephantContext.getServerUrl("http") + ShopContext.getInstance().getNotificationPath());
130  marker.put("okURL", ElephantContext.getServerUrl("http") + ShopContext.getInstance().getOKPath());
131  marker.put("koURL", ElephantContext.getServerUrl("http") + ShopContext.getInstance().getKOPath());
132  marker.process("cart", "self-test");
133  } else {
134  new RedsysPOS().addParameters(marker, cart.getTotalAmount(), cart.getResetOrder());
135  cart.serializeForOrder(contact);
136  marker.process("cart", "proceed");
137  }
138  break;
139  }
140  }
141 
142  public String getUrlForCheckout() {
144  if(c == null || !c.isWebUser()) {
145  return ElephantContext.getRootWebPath() + "/user";
146  } else {
148  }
149  }
150 
151  private void checkCheckout() {
152  RedsysPOS pos = new RedsysPOS();
153  if(pos.isOnlineNotification(constructor) || "true".equals(constructor.getParameter("selftest"))) {
154  Cart notifCart = ShopContext.getInstance().isSelfTestScope() ?
155  Cart.deserializeForOrder(constructor.getParameter("order")) :
156  pos.isAccepted(constructor);
157  if(notifCart != null && !notifCart.isEmpty() && notifCart.getContact().isWebUser()) {
158  // generate from cart
159  FinancialsCart fc = new FinancialsCart(notifCart, getDao(), true);
160  Document doc = fc.generate();
161  // send notification
162  try {
163  if(doc != null) {
164  sendDocumentToLogistic(doc);
165  sendDocumentToCustomer(doc);
166  } else {
167  pos.logProperties();
168  sendCartToAdmin(notifCart);
169  }
170  } catch(Exception ex) {
171  pos.logProperties();
172  MailSenders.getPool()
173  .addAdministrators()
174  .send(ElephantContext.getSiteName() + ":SHOP-MAIL-NOT-SENT", "Problems while sending mail");
175  }
176  } else {
177  pos.logProperties();
178  MailSenders.getPool()
179  .addAdministrators()
180  .send(ElephantContext.getSiteName() + ":SHOP-DESERIALIZE", "Deserializing");
181  }
182  } else if(contact != null && contact.isWebUser()) {
183  Contact c = getContact(contact);
184  Address d = getAddress(ShopContext.getInstance().getDelivery());
185  Address f = getAddress(ShopContext.getInstance().getFiscal());
186  boolean needSave = false;
187  // process all possible values
188  // make changes only if different values
189  String gid = constructor.getParameter("gid");
190  if(!Strings.isBlank(gid)) {
191  c.setGlobalIdentifier(gid);
192  needSave = true;
193  }
194  String dstreet = constructor.getParameter("dstreet");
195  if(!Strings.isBlank(dstreet)) {
196  if(d == null) {
197  d = new Address();
198  d.setContact(c);
199  c.getAddresses().add(d);
200  d.setDescription(ShopContext.getInstance().getDelivery());
201  d.setOnlyOwner(false);
202  d.setOwner(contact.getId());
203  }
204  d.setStreet(dstreet);
205  needSave = true;
206  }
207  String dcity = constructor.getParameter("dcity");
208  if(!Strings.isBlank(dcity)) {
209  if(d != null) {
210  d.setCity(dcity);
211  }
212  }
213  String dzipcode = constructor.getParameter("dzipcode");
214  if(!Strings.isBlank(dzipcode)) {
215  if(d != null) {
216  d.setZipCode(dzipcode);
217  }
218  }
219  String dprovince = constructor.getParameter("dprovince");
220  if(!Strings.isBlank(dprovince)) {
221  if(d != null) {
222  d.setProvince(dprovince);
223  }
224  }
225  String dvalue = constructor.getParameter("dvalue");
226  if(!Strings.isBlank(dvalue)) {
227  cart.setDeliveryValue(dvalue);
228  }
229  String mobile = constructor.getParameter("mobile");
230  if(!Strings.isBlank(mobile)) {
231  c.getIContact().setConnector(ShopContext.getInstance().getContactPhone(), mobile);
232  needSave = true;
233  }
234  String fstreet = constructor.getParameter("fstreet");
235  if(!Strings.isBlank(fstreet)) {
236  if(f == null) {
237  f = new Address();
238  f.setContact(c);
239  c.getAddresses().add(f);
240  f.setDescription(ShopContext.getInstance().getFiscal());
241  f.setOnlyOwner(false);
242  f.setOwner(contact.getId());
243  }
244  f.setStreet(fstreet);
245  needSave = true;
246  }
247  String fcity = constructor.getParameter("fcity");
248  if(!Strings.isBlank(fcity)) {
249  if(f != null) {
250  f.setCity(fcity);
251  }
252  }
253  String fzipcode = constructor.getParameter("fzipcode");
254  if(!Strings.isBlank(fzipcode)) {
255  if(f != null) {
256  f.setZipCode(fzipcode);
257  }
258  }
259  String fprovince = constructor.getParameter("fprovince");
260  if(!Strings.isBlank(fprovince)) {
261  if(f != null) {
262  f.setProvince(fprovince);
263  }
264  }
265  if(needSave) {
266  c.setLocale(LocaleUtils.toLocale(ShopContext.getInstance().getLocale()));
267  c.setCurrency(Currency.getInstance(ShopContext.getInstance().getCurrency()));
268  contact.setContact(new ContactWrapper(c).save());
269  }
270  // Wants bill & pickup
271  if(cart.getStatus() == 2) {
272  String bill = constructor.getParameter("wantBill");
273  cart.setWantBill("true".equals(bill));
274  String dpickup = constructor.getParameter("dpickup");
275  cart.setPickup("true".equals(dpickup));
276  }
277  // Process step
278  if("1".equals(constructor.getParameter("nextStep"))) {
279  int max = checkMaximumStatus();
280  if(cart.getStatus() < max) {
281  if(cart.getStatus() + 1 == 3 && !cart.isWantBill() && max > 3) {
282  cart.setStatus(4);
283  } else if(cart.getStatus() + 1 <= max) {
284  cart.setStatus(cart.getStatus() + 1);
285  }
286  }
287  } else if("1".equals(constructor.getParameter("prevStep"))) {
288  if(cart.getStatus() - 1 == 3 && !cart.isWantBill()) {
289  cart.setStatus(2);
290  } else if(cart.getStatus() - 1 >= 0) {
291  cart.setStatus(cart.getStatus() - 1);
292  }
293  }
294  }
295  }
296 
297  private int checkMaximumStatus() {
298  if(contact == null || !contact.isWebUser() || cart == null || cart.isEmpty()) {
299  return 0;
300  }
301  if(cart.needsDelivery() && !cart.isPickup()) {
302  Address delivery = getAddress(ShopContext.getInstance().getDelivery());
303  if(!checkValidAddress(delivery)) {
304  return 2;
305  }
306  }
307  if(cart.isWantBill()) {
308  Address fiscal = getAddress(ShopContext.getInstance().getFiscal());
309  if(Strings.isBlank(contact.getGlobalId()) || !checkValidAddress(fiscal)) {
310  return 3;
311  }
312  }
313  return 4;
314  }
315 
316  private Address getAddress(String name) {
317  Address address = null;
318  if(contact != null && contact.isValid()) {
319  Contact c = getContact(contact);
320  if(Strings.isBlank(name)) {
321  address = c.getAddressMap().get(ShopContext.getInstance().getDelivery());
322  if(address == null) {
323  address = c.getAddressMap().get(ShopContext.getInstance().getFiscal());
324  }
325  } else {
326  address = c.getAddressMap().get(name);
327  }
328  }
329  return address;
330  }
331 
332  private Dao _dao;
333 
334  private Dao getDao() {
335  if(_dao == null) {
336  _dao = new FinancialsPU();
337  }
338  return _dao;
339  }
340 
341  private Contact getContact(IContact contact) {
342  return (Contact) contact.getContact();
343  }
344 
345  private boolean checkValidAddress(Address address) {
346  return address != null && !address.isEmpty() && !Strings.isBlank(address.getCity()) && !Strings.isBlank(address.getZipCode());
347  }
348 
349  private void sendCartToAdmin(Cart notifCart) {
350  StringBuilder sb = new StringBuilder();
351  sb.append(notifCart.getContact().getName())
352  .append(": ")
353  .append(notifCart.getAmounts().getTotal())
354  .append("€\n")
355  .append(notifCart.getContact()
356  .getConnector(ShopContext.getInstance().getContactPhone()))
357  .append("\n");
358  for(CartItem ci : cart.getItems()) {
359  sb.append("\n")
360  .append(ci.getQuantity())
361  .append(" #")
362  .append(ci.getProduct().getProductCode())
363  .append(" ")
364  .append(ci.getProduct().getDescription())
365  .append(" ")
366  .append(ci.getPrice())
367  .append(" ")
368  .append(ci.getAmount());
369  }
370  MailSenders.getPool()
371  .addAdministrators()
372  .send(ElephantContext.getSiteName() + ":SHOP-ERROR", sb.toString());
373  }
374 
375  private void sendDocumentToLogistic(Document doc) {
376  StringBuilder sb = new StringBuilder();
377  sb.append(doc.getContract().getFullDescription())
378  .append("\n")
379  .append(doc.getDocumentString())
380  .append("\n")
381  .append(doc.getAmounts().getTotal())
382  .append("€\n")
383  .append(doc.getContract().getIContractor()
384  .getConnector(ShopContext.getInstance().getContactPhone()))
385  .append("\n");
386  for(DocumentLine di : doc.getDocumentLines()) {
387  sb.append("\n")
388  .append(di.getQuantity())
389  .append(" #")
390  .append(di.getProduct().getProductCode())
391  .append(" ")
392  .append(di.getProduct().getDescription())
393  .append(" ")
394  .append(di.getPrice())
395  .append(" ")
396  .append(di.getAmount());
397  }
398  sb.append(doc.getNotes());
399  MailSenders.getPool()
400  .addUser("Logistic", ShopContext.getInstance().getLogistic())
401  .send(ElephantContext.getSiteName() + ":SHOP", sb.toString());
402  }
403 
404  private void sendDocumentToCustomer(Document doc) throws EmailException {
405  Collection<IContact> emails = doc.getContract().getIParticipantsEmail();
406  if(emails != null) {
407  String mailString = getMailString(emails);
408  if(!Strings.isBlank(mailString)) {
409  try {
410  AttachCollection amc = new AttachCollection();
411  amc.loadAttachments(FinancialsPU.getObjectPath(doc), true);
412  amc.loadAttachments(FinancialsPU.getObjectPath(doc.getContract()) + "/Mail/" + doc.getDocumentDefinition().getName(), true);
413  Collection<MailAttachment> attachments = amc.getAttachments();
414  File attach = File.createTempFile("attach_", "_mail");
415  FileOutputStream fos = new FileOutputStream(attach);
416  GenerateDocument gd = new GenerateDocument();
417  gd.outputDocument(doc, true, fos);
418  MailAttachment ma = new MailAttachment(attach.getAbsolutePath(), doc.getDocDescription() + ".pdf", null);
419  ma.attachment = attach;
420  attachments.add(ma);
421  MailSenders.getPool()
422  .setRoot("/financials")
423  .addContacts(emails)
424  .addMailAttachments(attachments)
425  .onFinish((m) -> {
426  SystemLogger.getInstance().doLog(SystemLogType.LOG_INFO, doc, "sent", mailString);
427  amc.removeAttachments();
428  })
429  .put("comment", StringParser.toHTML(doc.getFullNotes()))
430  .put("title", doc.getDocDescription())
431  .put("mas", attachments)
432  .sendTemplate("document", ElephantContext.getSiteName() + ": " + doc.getDocDescription());
433  } catch (IOException ex) {
434  Logger.getLogger(Checkout.class.getName()).log(Level.SEVERE, ElephantContext.logMsg(mailString), ex);
435  }
436  }
437  }
438  }
439 
440  private String getMailString(Collection<IContact> iParticipantsEmail) {
441  PhraseBuilder pb = new PhraseBuilder();
442  for(IContact c : iParticipantsEmail) {
443  String email = c.getConnector(IUser.CONNECTOR_EMAIL);
444  if(Contacts.isValidEmail(email)) {
445  pb.addWord(c.getName() + ": " + email);
446  pb.addPendingSeparator(",");
447  }
448  }
449  return pb.toString();
450  }
451 
452 }
static String getServerUrl(String scheme)
static Cart deserializeForOrder(String order)
Definition: Cart.java:255
void setDeliveryValue(String deliveryValue)
Definition: Cart.java:90
void setStatus(int status)
Definition: Cart.java:66
CartItemSet getItems()
Definition: Cart.java:54
boolean addDeliveryItem(long productId, double quantity, double tax, double price)
Definition: Cart.java:117
void setPickup(boolean pickup)
Definition: Cart.java:82
void setWantBill(boolean wantBill)
Definition: Cart.java:74
void serializeForOrder(IContact contact)
Definition: Cart.java:241
boolean isOnlineNotification(IConstructor constructor)
Definition: RedsysPOS.java:82
void addParameters(ElephantMarker marker, double amount, String order)
Definition: RedsysPOS.java:46
Cart isAccepted(IConstructor constructor)
Definition: RedsysPOS.java:113
static Cart getCart(IConstructor constructor)
Checkout(IConstructor constructor)
Definition: Checkout.java:71
void process(String rootTmpl, String tmpl)
Object put(Object key, Object value)
void setContact(Object contact)