package org.multibit.mbm.client.domain.model.pricing;
import com.google.common.base.Optional;
import com.google.common.collect.Lists;
import com.xeiam.xchange.currency.MoneyUtils;
import org.joda.money.BigMoney;
import org.joda.time.DateTime;
import org.multibit.mbm.client.domain.model.model.Customer;
import org.multibit.mbm.client.domain.model.model.PricingRule;
import org.multibit.mbm.client.domain.model.model.Supplier;
import org.multibit.mbm.client.common.utils.DateUtils;
import java.util.List;
/**
* <p>Business object to provide the following to {@link org.multibit.mbm.client.domain.model.model.Item}:</p>
* <ul>
* <li>Calculation of price based on purchase order</li>
* </ul>
* <p>A price can only be determined as a result of the application of rules against
* and original value.</p>
*
* @since 0.0.1
*
*/
public class PriceBuilder {
private int quantity = 0;
private DateTime start = DateUtils.nowUtc();
private DateTime end = DateUtils.nowUtc();
private BigMoney startingPrice = MoneyUtils.parse("GBP 0.0");
private Optional<Customer> customer = Optional.absent();
private Optional<Supplier> supplier = Optional.absent();
private List<PricingRule> pricingRules = Lists.newArrayList();
private boolean isBuilt = false;
/**
* @return A new instance of the builder
*/
public static PriceBuilder newInstance() {
return new PriceBuilder();
}
public PriceBuilder() {
}
/**
* Handles the building process. No further configuration is possible after this.
*/
public BigMoney build() {
validateState();
// Price is not a DTO
BigMoney price = startingPrice;
for (PricingRule pricingRule : pricingRules) {
pricingRule.setCustomer(customer);
pricingRule.setSupplier(supplier);
pricingRule.setQuantity(quantity);
// TODO Consider date ranges (use discriminator value e.g. R(A,B], R(o,o))
// Test filtering rules
if (pricingRule.skip()) {
continue;
}
if (pricingRule.halt()) {
break;
}
price = pricingRule.applyTo(price);
}
isBuilt = true;
return price;
}
private void validateState() {
if (isBuilt) {
throw new IllegalStateException("The entity has been built");
}
}
public PriceBuilder withPricingRule(PricingRule pricingRule) {
pricingRules.add(pricingRule);
return this;
}
/**
* Add the Customer in case it affects the price (one permitted)
*
* @return The builder
*/
public PriceBuilder withCustomer(Customer customer) {
this.customer = Optional.fromNullable(customer);
return this;
}
/**
* Add the Supplier in case it affects the price (one permitted)
*
* @return The builder
*/
public PriceBuilder withSupplier(Supplier supplier) {
this.supplier = Optional.fromNullable(supplier);
return this;
}
/**
* @param startingPrice The starting price (default is GBP0.0)
*
* @return The builder
*/
public PriceBuilder withStartingPrice(BigMoney startingPrice) {
this.startingPrice = startingPrice;
return this;
}
}