BrightSide Workbench Full Report + Source Code
Product.java
Go to the documentation of this file.
1 /*
2  * TurrĂ³ i Cutiller Foundation. License notice.
3  * Copyright (C) 2011 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 package org.turro.financials.entity;
19 
20 import java.util.*;
21 import javax.persistence.*;
22 import org.turro.string.Strings;
23 import org.turro.elephant.db.IdUtils;
24 import org.turro.elephant.db.WhereClause;
25 import org.turro.fieldit.FieldItSet;
26 import org.turro.fieldit.FieldItUtil;
27 import org.turro.fieldit.IValueItEntity;
28 import org.turro.fieldit.ValueItSet;
29 import org.turro.financials.db.FinancialsPU;
30 import org.turro.financials.product.IProduct;
31 import org.turro.financials.product.Movement;
32 import org.turro.groupit.GroupItUtil;
33 import org.turro.jpa.Dao;
34 import org.turro.jpa.entity.IDaoEntity;
35 import org.turro.math.Round;
36 import org.turro.reflection.MappingSet;
37 import org.turro.util.Chars;
38 
43 @Entity
44 public class Product implements java.io.Serializable, IDaoEntity, IProduct, IValueItEntity {
45 
46  @Id
47  @GeneratedValue(strategy=GenerationType.IDENTITY)
48  @Column(name="IDENTIFIER")
49  private long id;
50 
51  private String productCode, description, keywords;
52 
53  private double price, tax;
54 
55  private boolean publishable, service, promoted, delivery, concept, attachments;
56 
57  @OneToMany(mappedBy = "product", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval=true)
58  private Set<ProductByContractor> productByContractors = new HashSet<>();
59 
60  public String getDescription() {
61  return description;
62  }
63 
64  public void setDescription(String description) {
65  this.description = description;
66  }
67 
68  public long getId() {
69  return id;
70  }
71 
72  public void setId(long id) {
73  this.id = id;
74  }
75 
76  public String getKeywords() {
77  return keywords;
78  }
79 
80  public void setKeywords(String keywords) {
81  this.keywords = keywords;
82  }
83 
84  public double getPrice() {
85  return price;
86  }
87 
88  public void setPrice(double price) {
89  this.price = price;
90  }
91 
92  public Set<ProductByContractor> getProductByContractors() {
93  return productByContractors;
94  }
95 
96  public void setProductByContractors(Set<ProductByContractor> productByContractors) {
97  this.productByContractors = productByContractors;
98  }
99 
100  public String getProductCode() {
101  return productCode;
102  }
103 
104  public void setProductCode(String productCode) {
105  this.productCode = productCode;
106  }
107 
108  public double getTax() {
109  return tax;
110  }
111 
112  public void setTax(double tax) {
113  this.tax = tax;
114  }
115 
116  public boolean isPublishable() {
117  return publishable;
118  }
119 
120  public void setPublishable(boolean publishable) {
121  this.publishable = publishable;
122  }
123 
124  public boolean isService() {
125  return service;
126  }
127 
128  public void setService(boolean service) {
129  this.service = service;
130  }
131 
132  public boolean isPromoted() {
133  return promoted;
134  }
135 
136  public void setPromoted(boolean promoted) {
137  this.promoted = promoted;
138  }
139 
140  public boolean isDelivery() {
141  return delivery;
142  }
143 
144  public void setDelivery(boolean delivery) {
145  this.delivery = delivery;
146  }
147 
148  public boolean isConcept() {
149  return concept;
150  }
151 
152  public void setConcept(boolean concept) {
153  this.concept = concept;
154  }
155 
156  public boolean isAttachments() {
157  return attachments;
158  }
159 
160  public void setAttachments(boolean attachments) {
161  this.attachments = attachments;
162  }
163 
164  /* IDaoEntity */
165 
166  @Override
167  public Object entityId() {
168  return id;
169  }
170 
171  @Override
172  public boolean isEmpty() {
173  return Strings.isBlank(description);
174  }
175 
176  @Override
177  public void prepareSave() {
178  if(Strings.isBlank(productCode)) {
179  productCode = IdUtils.getNewLongIdFromString(new FinancialsPU(), "Product", "productCode") + "";
180  }
181  }
182 
183  /* Helpers */
184 
185  public String getDescription(boolean fields) {
186  return description +
187  (Strings.isBlank(keywords) ? "" : " " + keywords) +
188  (fields ? getFieldDescription() : "");
189  }
190 
191  public String getFieldDescription() {
192  String extra = getValues().getDescriptionFields();
193  return Strings.isBlank(extra) ? "" : " " + extra;
194  }
195 
196  public double getPriceWithTax(int fractions) {
197  double taxable = new Round(price).decimals(fractions).value();
198  return new Round((taxable * (1.0 + tax / 100.0))).decimals(fractions).value();
199  }
200 
201  /* IProduct */
202 
203  private transient ProductByContractor productByContractor;
204  private transient Double lastCost = null, lastCostTax = null,
205  lastPrice = null, lastPriceTax = null;
206 
207  @Override
209  return productByContractor;
210  }
211 
212  @Override
213  public void setProductByContractor(ProductByContractor productByContractor) {
214  this.productByContractor = productByContractor;
215  }
216 
217  @Override
218  public long getProductId() {
219  return id;
220  }
221 
222  @Override
223  public String getProductCodeStr() {
224  return productCode;
225  }
226 
227  @Override
228  public double getProductCost() {
229  if(lastCost == null) {
230  Object d[] = loadData(1);
231  lastCost = (Double) d[0];
232  lastCostTax = (Double) d[1];
233  }
234  return lastCost;
235  }
236 
237  @Override
238  public double getProductCostTax() {
239  if(lastCost == null) {
240  Object d[] = loadData(1);
241  lastCost = (Double) d[0];
242  lastCostTax = (Double) d[1];
243  }
244  return lastCostTax;
245  }
246 
247  @Override
248  public double getProductPrice() {
249  if(price == 0.0d) {
250  if(lastPrice == null) {
251  Object d[] = loadData(-1);
252  lastPrice = (Double) d[0];
253  lastPriceTax = (Double) d[1];
254  }
255  return lastPrice;
256  }
257  return price;
258  }
259 
260  @Override
261  public double getProductPriceTax() {
262  if(tax == 0.0d) {
263  if(lastPrice == null) {
264  Object d[] = loadData(-1);
265  lastPrice = (Double) d[0];
266  lastPriceTax = (Double) d[1];
267  }
268  return lastPriceTax;
269  }
270  return tax;
271  }
272 
273  @Override
274  public IProduct load(Object id) {
275  throw new UnsupportedOperationException("Not supported yet.");
276  }
277 
278  @Override
279  public String getProductName() {
280  return description;
281  }
282 
283  @Override
284  public double getProductStock(Date date, Contract store) {
285  return getStock(store, date);
286 // WhereClause wc = new WhereClause();
287 // wc.addClause("select coalesce(sum(quantity*dl.lineType.stockCoefficient*1.0),0.0) ");
288 // wc.addClause("from DocumentLine dl");
289 // wc.addClause("where dl.product = :product");
290 // wc.addNamedValue("product", this);
291 // if(store != null) {
292 // wc.addClause("and dl.store = :store");
293 // wc.addNamedValue("store", store);
294 // }
295 // wc.addClause("and dl.lineType.stockCoefficient <> 0");
296 // wc.addClause("and dl.quantity <> 0");
297 // if(date != null) {
298 // wc.addClause("and dl.document.receiptDate <= :date");
299 // wc.addNamedValue("date", date);
300 // }
301 // Double stock = (Double) new FinancialsPU().getSingleResultOrNull(wc);
302 // return stock == null ? 0.0 : stock;
303  }
304 
305  @Override
306  public String getProductString() {
307  if(productByContractor != null &&
308  productByContractor.getContract() != null &&
309  productByContractor.getContract().isUseContractorCode()) {
310  return "##" + productByContractor.getContractorCode() + Chars.forward().spaced() + getDescription(true);
311  } else {
312  return "#" + productCode + Chars.forward().spaced() + getDescription(true);
313  }
314  }
315 
316  @Override
317  public boolean isUncoded() {
318  return false;
319  }
320 
321  @Override
322  public Collection<Movement> getMovements() {
323  WhereClause wc = new WhereClause();
324  wc.addClause("select new org.turro.financials.product.Movement");
325  wc.addClause("(dl.document.contract, dl.document.documentDate,");
326  wc.addClause("dl.lineType.stockCoefficient,dl.quantity,dl.price,dl.concept)");
327  wc.addClause("from DocumentLine dl");
328  wc.addClause("where (dl.product = :product");
329  wc.addNamedValue("product", this);
330  wc.addClause("or dl.productByContractor = :pbc)");
331  wc.addNamedValue("pbc", productByContractor);
332  wc.addClause("and dl.quantity <> 0");
333  wc.addClause("order by dl.document.receiptDate desc, dl.lineOrder");
334  return new FinancialsPU().getResultList(wc, 100);
335  }
336 
337  @Override
338  public Collection<Movement> getMovements(Date from, Date to, Contract store) {
339  WhereClause wc = new WhereClause();
340  wc.addClause("select new org.turro.financials.product.Movement");
341  wc.addClause("('Accumulated',coalesce(sum(dl.quantity*dl.lineType.stockCoefficient),0.0),coalesce(sum(dl.quantity*dl.price*dl.lineType.stockCoefficient),0.0))");
342  wc.addClause("from DocumentLine dl");
343  wc.addClause("where (dl.product = :product");
344  wc.addNamedValue("product", this);
345  wc.addClause("or dl.productByContractor = :pbc)");
346  wc.addNamedValue("pbc", productByContractor);
347  if(store != null) {
348  wc.addClause("and dl.store = :store");
349  wc.addNamedValue("store", store);
350  }
351  wc.addClause("and dl.quantity <> 0");
352  wc.addClause("and dl.document.receiptDate < :from2");
353  wc.addNamedValue("from2", from);
354  Collection<Movement> movs = new FinancialsPU().getResultList(wc);
355  wc = new WhereClause();
356  wc.addClause("select new org.turro.financials.product.Movement");
357  wc.addClause("(dl.document.contract, dl.document.documentDate,");
358  wc.addClause("dl.lineType.stockCoefficient,dl.quantity,dl.price,dl.concept)");
359  wc.addClause("from DocumentLine dl");
360  wc.addClause("where (dl.product = :product");
361  wc.addNamedValue("product", this);
362  wc.addClause("or dl.productByContractor = :pbc)");
363  wc.addNamedValue("pbc", productByContractor);
364  if(store != null) {
365  wc.addClause("and dl.store = :store");
366  wc.addNamedValue("store", store);
367  }
368  wc.addClause("and dl.quantity <> 0");
369  wc.addClause("and dl.document.receiptDate >= :from2");
370  wc.addNamedValue("from2", from);
371  if(to != null) {
372  wc.addClause("and dl.document.receiptDate <= :to2");
373  wc.addNamedValue("to2", to);
374  }
375  wc.addClause("order by dl.document.receiptDate asc, dl.lineOrder");
376  movs.addAll(new FinancialsPU().getResultList(wc));
377  return movs;
378  }
379 
380  public ProductRegulation getLastInventory(Dao dao, Contract store, Date date) {
381  WhereClause wc = new WhereClause();
382  wc.addClause("select pr from ProductRegulation pr");
383  wc.addClause("where pr.product = :product");
384  wc.addNamedValue("product", this);
385  wc.addClause("and pr.store = :store");
386  wc.addNamedValue("store", store);
387  wc.addClause("and pr.type = :type");
389  wc.addClause("and pr.regulationDate = ");
390  wc.addClause("(select max(pr2.regulationDate) from ProductRegulation pr2");
391  wc.addClause("where pr2.product = pr.product");
392  wc.addClause("and pr2.regulationDate <= :date");
393  wc.addNamedValue("date", date);
394  wc.addClause("and pr2.store = pr.store");
395  wc.addClause("and pr2.type = pr.type)");
396  return (ProductRegulation) dao.getSingleResultOrNull(wc);
397  }
398 
399  public double getStock(Contract store, Date date) {
400  Dao dao = new FinancialsPU();
401  ProductRegulation pr = getLastInventory(dao, store, date);
402  double stock = pr == null ? 0.0 : pr.getQuantity();
403  WhereClause wc = new WhereClause();
404  wc.addClause("select coalesce(sum(dl.quantity*dl.lineType.stockCoefficient),0.0)");
405  wc.addClause("from DocumentLine dl");
406  wc.addClause("where dl.product = :product");
407  wc.addNamedValue("product", this);
408  wc.addClause("and dl.store = :store");
409  wc.addNamedValue("store", store);
410  wc.addClause("and dl.quantity <> 0");
411  wc.addClause("and dl.document.receiptDate <= :date");
412  wc.addNamedValue("date", date);
413  if(pr != null) {
414  wc.addClause("and dl.document.receiptDate >= :from");
415  wc.addNamedValue("from", pr.getRegulationDate());
416  }
417  Double result = (Double) dao.getSingleResultOrNull(wc);
418  stock += result == null ? 0.0 : result;
419  wc = new WhereClause();
420  wc.addClause("select sum(quantity)");
421  wc.addClause("from ProductRegulation pr");
422  wc.addClause("where pr.product = :product");
423  wc.addNamedValue("product", this);
424  wc.addClause("and pr.store = :store");
425  wc.addNamedValue("store", store);
426  wc.addClause("and pr.type <> :type");
428  wc.addClause("and pr.regulationDate <= :date");
429  wc.addNamedValue("date", date);
430  if(pr != null) {
431  wc.addClause("and pr.regulationDate >= :from");
432  wc.addNamedValue("from", pr.getRegulationDate());
433  }
434  result = (Double) dao.getSingleResultOrNull(wc);
435  stock += result == null ? 0.0 : result;
436  return stock;
437  }
438 
439  public static List<Product> getProducts() {
440  return getProducts(null, false);
441  }
442 
443  public static Product getProductByCode(String code) {
444  WhereClause wc = new WhereClause();
445  wc.addClause("select prod from Product prod where productCode = :code");
446  wc.addNamedValue("code", code);
447  return (Product) new FinancialsPU().getSingleResultOrNull(wc);
448  }
449 
450  public static List<Product> getProducts(String concept, boolean equality) {
451  WhereClause wc = new WhereClause();
452  wc.addClause("select prod");
453  getDescriptionQuery(wc, concept, equality);
454  List<Product> list = new FinancialsPU().getResultList(wc);
455  return list;
456  }
457 
458  private static void getDescriptionQuery(WhereClause wc, String description, boolean equality) {
459  wc.addClause("from Product prod");
460  if(!Strings.isBlank(description)) {
461  wc.addClause("where 1=1");
462  if(equality) {
463  wc.addClause("and prod.description = :desc");
464  wc.addNamedValue("desc", description);
465  } else {
466  wc.addLikeFields(new String[] { "prod.description" }, description);
467  }
468  } else {
469  wc.addClause("where 1=2");
470  }
471  wc.addClause("order by prod.description");
472  }
473 
474  private Object[] loadData(double coefficient) {
475  WhereClause wc = new WhereClause();
476  wc.addClause("select dl.price, dl.tax");
477  wc.addClause("from DocumentLine dl");
478  wc.addClause("where dl.product = :product");
479  wc.addNamedValue("product", this);
480  wc.addClause("or dl.productByContractor = :pbc");
481  wc.addNamedValue("pbc", productByContractor);
482  wc.addClause("and dl.lineType.stockCoefficient = :coef");
483  wc.addNamedValue("coef", coefficient);
484  wc.addClause("and dl.quantity <> 0");
485  wc.addClause("order by dl.document.receiptDate desc, dl.lineOrder");
486  List l = new FinancialsPU().getResultList(wc, 1);
487  Object d[];
488  if(!l.isEmpty()) {
489  d = (Object[]) l.get(0);
490  } else {
491  d = new Double[] { 0.0, 0.0 };
492  }
493  return d;
494  }
495 
496  /* Fields */
497 
498  @Override
501  }
502 
503  @Override
506  }
507 
508  @Override
509  public Object getFieldValue(String label) {
511  }
512 
513  @Override
514  public Collection<IValueItEntity> getRelated() {
515  Collection<String> paths = FieldItUtil.related(FinancialsPU.getObjectPath(this));
516  return new ArrayList<>();
517  }
518 
519  /* XML Serializer */
520 
521  public MappingSet getSerializerMappings() {
522  MappingSet set = new MappingSet();
523  set.addMapping(Product.class, 1,
524  new String[] { "id", "productCode", "description", "keywords", "price", "tax",
525  "publishable", "service", "promoted", "delivery", "concept", "attachments" },
526  new String[] { "productByContractors" });
527  set.addMapping(ProductByContractor.class, 2,
528  new String[] { "contractorCode", "price", "tax" },
529  new String[] { "contract" });
530  set.addMapping(Contract.class, 3,
531  new String[] { "id", "name" },
532  null);
533  return set;
534  }
535 
536 }
static long getNewLongIdFromString(Dao dao, String table, String field)
Definition: IdUtils.java:61
void addLikeFields(String[] fields, String value)
void addNamedValue(String name, Object value)
static Collection< String > related(String path)
static Object getFieldValue(String label, String entityPath)
static String getObjectPath(Object object)
void setConcept(boolean concept)
Definition: Product.java:152
Collection< Movement > getMovements()
Definition: Product.java:322
ProductRegulation getLastInventory(Dao dao, Contract store, Date date)
Definition: Product.java:380
Collection< Movement > getMovements(Date from, Date to, Contract store)
Definition: Product.java:338
static List< Product > getProducts(String concept, boolean equality)
Definition: Product.java:450
double getProductStock(Date date, Contract store)
Definition: Product.java:284
Set< ProductByContractor > getProductByContractors()
Definition: Product.java:92
void setAttachments(boolean attachments)
Definition: Product.java:160
Object getFieldValue(String label)
Definition: Product.java:509
void setPromoted(boolean promoted)
Definition: Product.java:136
void setProductByContractor(ProductByContractor productByContractor)
Definition: Product.java:213
String getDescription(boolean fields)
Definition: Product.java:185
double getPriceWithTax(int fractions)
Definition: Product.java:196
void setPublishable(boolean publishable)
Definition: Product.java:120
void setService(boolean service)
Definition: Product.java:128
ProductByContractor getProductByContractor()
Definition: Product.java:208
void setProductByContractors(Set< ProductByContractor > productByContractors)
Definition: Product.java:96
void setProductCode(String productCode)
Definition: Product.java:104
static List< Product > getProducts()
Definition: Product.java:439
void setDescription(String description)
Definition: Product.java:64
Collection< IValueItEntity > getRelated()
Definition: Product.java:514
void setKeywords(String keywords)
Definition: Product.java:80
void setDelivery(boolean delivery)
Definition: Product.java:144
static Product getProductByCode(String code)
Definition: Product.java:443
double getStock(Contract store, Date date)
Definition: Product.java:399
static ValueItSet getValues(String entityPath)
static FieldItSet getFields(String entityPath)
Object getSingleResultOrNull(SqlClause sc)
Definition: Dao.java:419
Round decimals(int digits)
Definition: Round.java:32