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