001package scpc.model.support; 002 003import java.math.BigDecimal; 004import javax.script.ScriptException; 005import org.slf4j.Logger; 006import org.slf4j.LoggerFactory; 007import scpc.Calculator; 008import scpc.model.IChainRule; 009import scpc.model.IRule; 010import scpc.model.SingleItem; 011 012/** 013 * Implement basic function of {@link IRule} 014 * 015 * @author Kent Yeh 016 * @param <T> type of real cart item. 017 */ 018public abstract class AbstractRuleBase<T> implements IRule<T> { 019 020 private static final Logger logger = LoggerFactory.getLogger(AbstractRuleBase.class); 021 022 private int containsCount = 0; 023 private BigDecimal containsSumOfOriginalPrice = BigDecimal.ZERO; 024 private BigDecimal containsSumOfSalePrice = BigDecimal.ZERO; 025 private BigDecimal sumOfSerialOriginalPrice = BigDecimal.ZERO; 026 private BigDecimal serialSumOfSalePrice = BigDecimal.ZERO; 027 private IChainRule<T> previousRule = null; 028 private String triggerFormula = ""; 029 private String quantityFormula = ""; 030 private EvalHelper evalHelper = null; 031 032 /** 033 * A trigger formula is evaluated to determine whether to get a bonus or 034 * not. 035 * <br>走訪品項時決定是否觸發取得優惠品項的決策公式 036 * 037 * @return 038 */ 039 public String getTriggerFormula() { 040 return triggerFormula; 041 } 042 043 /** 044 * Setting a trigger formula is evaluated to determine whether to get a 045 * bonus or not. 046 * 047 * @param triggerFormula 048 */ 049 public void setTriggerFormula(String triggerFormula) { 050 this.triggerFormula = triggerFormula; 051 } 052 053 /** 054 * When triggered, a formula to check how many quantities should offer. 055 * <br>品項走訪觸發後,以公式決定優惠品項的數量 056 * 057 * @return 058 */ 059 public String getQuantityFormula() { 060 return isLeaf() ? quantityFormula : null; 061 } 062 063 /** 064 * Setting a formula to check how many quantities should offer after 065 * triggered. 066 * 067 * @param quantityFormula 068 */ 069 public void setQuantityFormula(String quantityFormula) { 070 this.quantityFormula = quantityFormula; 071 } 072 073 /** 074 * @see IRule#getPrevious() 075 * @return 076 */ 077 @Override 078 public IChainRule<T> getPrevious() { 079 return previousRule; 080 } 081 082 /** 083 * Set previous rule if exists. 084 * <br>如果是串連規則,設定前串連規則 085 * 086 * @param previousRule previous rule 087 */ 088 public void setPrevious(IChainRule<T> previousRule) { 089 this.previousRule = previousRule; 090 } 091 092 /** 093 * for {@link Calculator} use only. 094 * 095 * @return 096 */ 097 @Override 098 public IRule<T> containsCountInc() { 099 containsCount++; 100 return this; 101 } 102 103 /** 104 * @see IRule#getContainsCount() 105 * @return 106 */ 107 @Override 108 public int getContainsCount() { 109 return containsCount; 110 } 111 112 /** 113 * @see IRule#sumOfContainsOriginalPriceInc(java.math.BigDecimal) 114 * @param originalPrice 115 * @return 116 */ 117 @Override 118 public IRule<T> sumOfContainsOriginalPriceInc(BigDecimal originalPrice) { 119 containsSumOfOriginalPrice = containsSumOfOriginalPrice.add(originalPrice); 120 return this; 121 } 122 123 /** 124 * @see IRule#sumOfContainsSalePriceInc(java.math.BigDecimal) 125 * @param salePrice 126 * @return 127 */ 128 @Override 129 public IRule<T> sumOfContainsSalePriceInc(BigDecimal salePrice) { 130 containsSumOfSalePrice = containsSumOfSalePrice.add(salePrice.setScale(getPriceScale())); 131 return this; 132 } 133 134 /** 135 * @see IRule#getSumOfContainsOriginalPrice() 136 * @return 137 */ 138 @Override 139 public BigDecimal getSumOfContainsOriginalPrice() { 140 return containsSumOfOriginalPrice; 141 } 142 143 /** 144 * @see IRule#getSumOfContainsSalePrice() 145 * @return 146 */ 147 @Override 148 public BigDecimal getSumOfContainsSalePrice() { 149 return containsSumOfSalePrice; 150 } 151 152 /** 153 * @see IRule#getSumOfSerialOriginalPrice() 154 * @return 155 */ 156 @Override 157 public BigDecimal getSumOfSerialOriginalPrice() { 158 return sumOfSerialOriginalPrice; 159 } 160 161 /** 162 * @see IRule#getSumOfSerialSalePrice() 163 * @return 164 */ 165 @Override 166 public BigDecimal getSumOfSerialSalePrice() { 167 return serialSumOfSalePrice; 168 } 169 170 /** 171 * Setting the summary sale price of the same applicable items. 172 * <br>設定符合此規則的同品項售價小計 173 * 174 * @param serialSumOfSalePrice 175 */ 176 public void setSerialSumOfSalePrice(BigDecimal serialSumOfSalePrice) { 177 this.serialSumOfSalePrice = serialSumOfSalePrice; 178 } 179 180 /** 181 * @see IRule#sumOfSerialOriginalPriceInc(java.math.BigDecimal) 182 * @param saleprice 183 * @return 184 */ 185 @Override 186 public IRule<T> sumOfSerialOriginalPriceInc(BigDecimal saleprice) { 187 this.sumOfSerialOriginalPrice = this.sumOfSerialOriginalPrice.add(saleprice.setScale(getPriceScale())); 188 return this; 189 } 190 191 /** 192 * @see IRule#sumOfSerialSalePriceInc(java.math.BigDecimal) 193 * @param saleprice 194 * @return 195 */ 196 @Override 197 public IRule<T> sumOfSerialSalePriceInc(BigDecimal saleprice) { 198 this.serialSumOfSalePrice = this.serialSumOfSalePrice.add(saleprice.setScale(getPriceScale())); 199 return this; 200 } 201 202 /** 203 * @see IRule#resetSumOfSerialOriginalPrice() 204 * @return 205 */ 206 @Override 207 public IRule<T> resetSumOfSerialOriginalPrice() { 208 this.sumOfSerialOriginalPrice = BigDecimal.ZERO; 209 return this; 210 } 211 212 /** 213 * @see IRule#resetSumOfSerialSalePrice() 214 * @return 215 */ 216 @Override 217 public IRule<T> resetSumOfSerialSalePrice() { 218 this.serialSumOfSalePrice = BigDecimal.ZERO; 219 return this; 220 } 221 222 @Override 223 public void resetSumOfPrice() { 224 containsSumOfOriginalPrice = BigDecimal.ZERO; 225 containsSumOfSalePrice = BigDecimal.ZERO; 226 sumOfSerialOriginalPrice = BigDecimal.ZERO; 227 serialSumOfSalePrice = BigDecimal.ZERO; 228 } 229 230 /** 231 * A formula evaluator to help analysis. 232 * <br>公式解譯工具 233 * 234 * @return 235 */ 236 public EvalHelper getEvalHelper() { 237 return evalHelper; 238 } 239 240 public void setEvalHelper(EvalHelper evalHelper) { 241 this.evalHelper = evalHelper; 242 } 243 244 /** 245 * @see IRule#isTriggered(scpc.model.SingleItem) 246 * @param item 247 * @return 248 * @throws ScriptException 249 */ 250 @Override 251 public boolean isTriggered(SingleItem<T> item) throws ScriptException { 252 if (contains(item)) { 253 if (evalHelper == null) { 254 throw new RuntimeException("Not any evalHelper already setting yet!"); 255 } else { 256 boolean res = Boolean.TRUE.equals(evalHelper.bindVaribles(this, item).eval(getTriggerFormula())); 257 logger.debug("eval(\"{}\") = {}", getTriggerFormula(), res); 258 return res; 259 } 260 } else { 261 logger.debug("not triggered owing not counts"); 262 return false; 263 } 264 } 265 266 /** 267 * Quantity measure of bonus after {@link #isTriggered(scpc.model.SingleItem) 268 * }. 269 * * <br> 觸發觸發後,優惠品項的數量估值 270 * 271 * @return 272 * @throws ScriptException 273 */ 274 public double evalQuantity() throws ScriptException { 275 if (isLeaf()) { 276 if (evalHelper == null) { 277 throw new RuntimeException("Not any evalHelper already setting yet!"); 278 } else { 279 Number mb = (Number) evalHelper.eval(getQuantityFormula()); 280 logger.debug("evail quantity(\"{}\")={}", getQuantityFormula(), mb); 281 return mb.doubleValue(); 282 } 283 } else { 284 return 0d; 285 } 286 } 287 288}