diff --git a/Contracts/IBoxingCalculation.php b/Contracts/IBoxingCalculation.php new file mode 100644 index 0000000..06e1335 --- /dev/null +++ b/Contracts/IBoxingCalculation.php @@ -0,0 +1,10 @@ +calculate($order); + $immutable_order = $this->getOrder($country_code, $total, $discount, $box_type); + $order_adapter = new ShippingOrderAdapter($immutable_order); + $boxing_properties = new BoxingPropertiesAdapter($immutable_order); + + $shipping_cost = $this->makeShippingCalcultions($order_adapter, $boxing_properties); + + return $shipping_cost->getFomatedValue(); + } + + private function getOrder($country_code, $total, $discount = 0, $premium_box = false):Order + { + return new Order($country_code, $total, $discount, $premium_box); + } + + private function makeShippingCalcultions(IShippingOrder $order_adapter, IShippingBox $boxing_properties):IPrice + { + $calculator_facade = new ShippingCostCalculator(); + return $calculator_facade->calculate($order_adapter, $boxing_properties); } } \ No newline at end of file diff --git a/Orders/BoxingPropertiesAdapter.php b/Orders/BoxingPropertiesAdapter.php new file mode 100644 index 0000000..0ebab09 --- /dev/null +++ b/Orders/BoxingPropertiesAdapter.php @@ -0,0 +1,24 @@ +order = $order; + } + + public function getType(): string + { + //remember we are working with dummy data + //probably in real situtation you will get the type from database using the order_id + return $this->order->boxType(); + } +} \ No newline at end of file diff --git a/Orders/Order.php b/Orders/Order.php index 08134e6..744cbb1 100644 --- a/Orders/Order.php +++ b/Orders/Order.php @@ -15,11 +15,15 @@ class Order { private $country = "PL"; private $total = 50; + private $shipping_discount = 0; + private $box_type = "DEFAULT"; - public function __construct($country_code, $total) + public function __construct($country_code, $total, $shipping_discount, $box_type) { $this->country = $country_code; $this->total = $total; + $this->shipping_discount = $shipping_discount; + $this->box_type = $box_type; } public function getCountry() @@ -48,7 +52,7 @@ public function getClientDiscount(){ public function getClientShippingDiscountPL() { - return 10; + return $this->shipping_discount; } public function getClientShippingDiscountEU() @@ -60,4 +64,11 @@ public function getClientShippingDiscountWORLD() { return 0; } + + public function boxType() + { + return $this->box_type; + } + //please assume that there will be a lot more of code inside of this class + //imagine the worst code which you ever seen... this one is worse } \ No newline at end of file diff --git a/Orders/ShippingOrderAdapter.php b/Orders/ShippingOrderAdapter.php new file mode 100644 index 0000000..3ae3aff --- /dev/null +++ b/Orders/ShippingOrderAdapter.php @@ -0,0 +1,61 @@ +order = $order; + $this->boxing = new BoxingPropertiesAdapter($order); + } + + public function getCountry() + { + return $this->order->getCountry(); + } + + public function getTotalPl() + { + return $this->order->getTotalPl(); + } + + public function getTotalUk() + { + return $this->order->getTotalUk(); + } + + public function getTotalUs() + { + return $this->order->getTotalUs(); + } + + public function getShippingDiscount() + { + switch($this->order->getCountry()) + { + case "PL": + return $this->order->getClientShippingDiscountPL(); + case "UK": + return $this->order->getClientShippingDiscountEU(); + case "US": + return $this->order->getClientShippingDiscountWORLD(); + default: + return $this->order->getClientShippingDiscountWORLD(); + } + } + + public function getBoxingProperties(): IShippingBox + { + return $this->boxing; + } +} \ No newline at end of file diff --git a/Shipping/CalculationsDirector.php b/Shipping/CalculationsDirector.php new file mode 100644 index 0000000..66b47e6 --- /dev/null +++ b/Shipping/CalculationsDirector.php @@ -0,0 +1,33 @@ +calc_builder = $calc_builder; + } + + public function calculate():IPrice + { + //this is the main shipping cost calculation + $calculator = $this->calc_builder->useOrderTotal(); + + //these has to be always calculated as first after total order value + $discount_decorations = $this->calc_builder->useShippingDiscounts($calculator); + + //other calculations + $boxing_decorations = $this->calc_builder->useBoxPricing(); + + return $this->calc_builder->makeCalculations($discount_decorations, $boxing_decorations); + } +} \ No newline at end of file diff --git a/Shipping/CommonCalculations/AdditionalCalc.php b/Shipping/CommonCalculations/AdditionalCalc.php new file mode 100644 index 0000000..4b02d27 --- /dev/null +++ b/Shipping/CommonCalculations/AdditionalCalc.php @@ -0,0 +1,30 @@ +calc = $calculations_component; + $this->price_factory = new PriceFactory(); + } + + public function calculate(IShippingOrder $order): IPrice + { + $shipping_cost = $this->calc->calculate($order); + return $this->decorate($shipping_cost, $order); + } + + abstract protected function decorate(IPrice $shipping_cost, IShippingOrder $order): IPrice; +} \ No newline at end of file diff --git a/Shipping/CommonCalculations/BoxPricing/DefaultBox.php b/Shipping/CommonCalculations/BoxPricing/DefaultBox.php new file mode 100644 index 0000000..cfad859 --- /dev/null +++ b/Shipping/CommonCalculations/BoxPricing/DefaultBox.php @@ -0,0 +1,29 @@ +price_factory = new PriceFactory(); + } + + public function calculate(IShippingBox $boxing_properties): IPrice + { + return $this->price_factory->create($this->getCurrency(), $this->getCountryPrice()); + } + + +} \ No newline at end of file diff --git a/Shipping/CommonCalculations/BoxPricing/PremiumBox.php b/Shipping/CommonCalculations/BoxPricing/PremiumBox.php new file mode 100644 index 0000000..d0db2d8 --- /dev/null +++ b/Shipping/CommonCalculations/BoxPricing/PremiumBox.php @@ -0,0 +1,45 @@ +default_price = $calculations_component; + $this->price_factory = new PriceFactory(); + } + + public function calculate(IShippingBox $boxing_properties): IPrice + { + $shipping_cost = $this->default_price->calculate($boxing_properties); + return $this->decorate($shipping_cost, $boxing_properties); + } + + protected function decorate(IPrice $shipping_cost, IShippingBox $boxing_properties):IPrice + { + if($boxing_properties->getType() === $this->getCurrentType()) + { + $price_summary = $shipping_cost->getValue() + $this->getCountryPrice(); + $shipping_cost = $this->price_factory->create($shipping_cost->getCurrencyCode(), $price_summary); + } + + return $shipping_cost; + } +} \ No newline at end of file diff --git a/Shipping/CommonCalculations/CalculationsBuilder.php b/Shipping/CommonCalculations/CalculationsBuilder.php new file mode 100644 index 0000000..95cf376 --- /dev/null +++ b/Shipping/CommonCalculations/CalculationsBuilder.php @@ -0,0 +1,46 @@ +order = $order; + $this->order_total = $order_total; + $this->boxing_properties = $boxing_properties; + } + + public function useShippingDiscounts(ICountryShippingCalc $calculations_component):ICountryShippingCalc + { + $free_days_decorator = new FreeDeliveryDays($calculations_component); + $client_discount_decorator = new ClientShippingDiscount($free_days_decorator); + + return $client_discount_decorator; + } + + public function useOrderTotal():ICountryShippingCalc + { + return $this->order_total; + } + + public function makeCalculations(ICountryShippingCalc $calculations_component, IBoxingCalculation $boxing_component): IPrice + { + $shipping_cost = $calculations_component->calculate($this->order); + $boxing_cost = $boxing_component->calculate($this->boxing_properties); + + //todo + return $shipping_cost->add($boxing_cost); + } +} \ No newline at end of file diff --git a/Shipping/CommonCalculations/ClientShippingDiscount.php b/Shipping/CommonCalculations/ClientShippingDiscount.php new file mode 100644 index 0000000..8ef0738 --- /dev/null +++ b/Shipping/CommonCalculations/ClientShippingDiscount.php @@ -0,0 +1,26 @@ +getShippingDiscount() > 0 ) + { + if($order->getShippingDiscount() >= $shipping_cost->getValue()) + { + $shipping_cost = $this->price_factory->create($shipping_cost->getCurrencyCode(), 0); + } else { + $after_discount = $shipping_cost->getValue() - $order->getShippingDiscount(); + $shipping_cost = $this->price_factory->create($shipping_cost->getCurrencyCode(), $after_discount); + } + } + + return $shipping_cost; + } +} \ No newline at end of file diff --git a/Shipping/CommonCalculations/FreeDeliveryDays.php b/Shipping/CommonCalculations/FreeDeliveryDays.php new file mode 100644 index 0000000..ef24704 --- /dev/null +++ b/Shipping/CommonCalculations/FreeDeliveryDays.php @@ -0,0 +1,28 @@ +isSpecialDay()) + { + $shipping_cost = $this->price_factory->create($shipping_cost->getCurrencyCode(), 0); + } + + return $shipping_cost; + } + + private function isSpecialDay() + { + return false; + } +} \ No newline at end of file diff --git a/Shipping/CommonCalculations/Price.php b/Shipping/CommonCalculations/Price.php new file mode 100644 index 0000000..9845687 --- /dev/null +++ b/Shipping/CommonCalculations/Price.php @@ -0,0 +1,23 @@ +getCurrencyCode() === $this->getCurrencyCode()) + { + $this->value = $value->getValue() + $this->getValue(); + return $this; + } + + throw new \Exception("Trying to add different currencies is not allowed"); + } +} \ No newline at end of file diff --git a/Shipping/Countries/OtherCountries/BoxPricing/DefaultBoxWorld.php b/Shipping/Countries/OtherCountries/BoxPricing/DefaultBoxWorld.php new file mode 100644 index 0000000..d12b72c --- /dev/null +++ b/Shipping/Countries/OtherCountries/BoxPricing/DefaultBoxWorld.php @@ -0,0 +1,20 @@ +boxing_properties); + $box_price_decorator = new PremiumBoxWorld($default_box); + + return $box_price_decorator; + } +} \ No newline at end of file diff --git a/Shipping/Countries/OtherCountries/OrderTotalWorld.php b/Shipping/Countries/OtherCountries/OrderTotalWorld.php new file mode 100644 index 0000000..d0d1b35 --- /dev/null +++ b/Shipping/Countries/OtherCountries/OrderTotalWorld.php @@ -0,0 +1,18 @@ +value = $value; + } + + public function getValue() + { + return $this->value; + } + + public function getCurrencyCode() + { + return $this->currency_code; + } + + public function getFomatedValue() + { + return $this->currency_code.$this->value; + } +} \ No newline at end of file diff --git a/Shipping/Countries/Pl/BoxPricing/DefaultBoxPl.php b/Shipping/Countries/Pl/BoxPricing/DefaultBoxPl.php new file mode 100644 index 0000000..bdf49b0 --- /dev/null +++ b/Shipping/Countries/Pl/BoxPricing/DefaultBoxPl.php @@ -0,0 +1,21 @@ +boxing_properties); + + $box_price_decorator = new PremiumBoxPl($default_box); + + return $box_price_decorator; + } +} \ No newline at end of file diff --git a/Shipping/Countries/Pl/OrderTotalPl.php b/Shipping/Countries/Pl/OrderTotalPl.php new file mode 100644 index 0000000..fdddeb1 --- /dev/null +++ b/Shipping/Countries/Pl/OrderTotalPl.php @@ -0,0 +1,20 @@ +getTotalPl(); + if($total > 100) + { + return new PricePl(0); + } + //there will be more logic in the future + return new PricePl(25); + } +} \ No newline at end of file diff --git a/Shipping/Countries/Pl/PricePL.php b/Shipping/Countries/Pl/PricePL.php new file mode 100644 index 0000000..c3c7d5e --- /dev/null +++ b/Shipping/Countries/Pl/PricePL.php @@ -0,0 +1,32 @@ +value = $value; + } + + public function getValue() + { + return $this->value; + } + + public function getCurrencyCode() + { + return $this->currency_code; + } + + public function getFomatedValue() + { + return $this->value.$this->currency_code; + } + +} \ No newline at end of file diff --git a/Shipping/Countries/Uk/BoxPricing/DefaultBoxUk.php b/Shipping/Countries/Uk/BoxPricing/DefaultBoxUk.php new file mode 100644 index 0000000..e279cc6 --- /dev/null +++ b/Shipping/Countries/Uk/BoxPricing/DefaultBoxUk.php @@ -0,0 +1,20 @@ +boxing_properties); + $premium_box_decorator = new PremiumBoxUk($default_box); + $uefa_champion_decorator = new UefaChampionBox($premium_box_decorator); + + return $uefa_champion_decorator; + } +} \ No newline at end of file diff --git a/Shipping/Countries/Uk/OrderTotalUk.php b/Shipping/Countries/Uk/OrderTotalUk.php new file mode 100644 index 0000000..918e9e9 --- /dev/null +++ b/Shipping/Countries/Uk/OrderTotalUk.php @@ -0,0 +1,21 @@ +getTotalUk(); + + if($total > 300) + { + return new PriceUk(0); + } + //there will be more logic in the future + return new PriceUk(25); + } +} \ No newline at end of file diff --git a/Shipping/Countries/Uk/PriceUk.php b/Shipping/Countries/Uk/PriceUk.php new file mode 100644 index 0000000..18611be --- /dev/null +++ b/Shipping/Countries/Uk/PriceUk.php @@ -0,0 +1,31 @@ +value = $value; + } + + public function getValue() + { + return $this->value; + } + + public function getCurrencyCode() + { + return $this->currency_code; + } + + public function getFomatedValue() + { + return $this->value.$this->currency_code; + } +} \ No newline at end of file diff --git a/Shipping/Countries/Us/BoxPricing/DefaultBoxUs.php b/Shipping/Countries/Us/BoxPricing/DefaultBoxUs.php new file mode 100644 index 0000000..9ccbc5a --- /dev/null +++ b/Shipping/Countries/Us/BoxPricing/DefaultBoxUs.php @@ -0,0 +1,20 @@ +boxing_properties); + $box_price_decorator = new PremiumBoxUs($default_box); + + return $box_price_decorator; + } +} \ No newline at end of file diff --git a/Shipping/Countries/Us/OrderTotalUs.php b/Shipping/Countries/Us/OrderTotalUs.php new file mode 100644 index 0000000..182d3c2 --- /dev/null +++ b/Shipping/Countries/Us/OrderTotalUs.php @@ -0,0 +1,21 @@ +getTotalUs(); + + if($total > 1000) + { + return new PriceUs(0); + } + //there will be more logic in the future + return new PriceUs(250); + } +} \ No newline at end of file diff --git a/Shipping/Countries/Us/PriceUs.php b/Shipping/Countries/Us/PriceUs.php new file mode 100644 index 0000000..c7f4a2b --- /dev/null +++ b/Shipping/Countries/Us/PriceUs.php @@ -0,0 +1,31 @@ +value = $value; + } + + public function getValue() + { + return $this->value; + } + + public function getCurrencyCode() + { + return $this->currency_code; + } + + public function getFomatedValue() + { + return $this->currency_code.$this->value; + } +} \ No newline at end of file diff --git a/Shipping/CountryCalcFactory.php b/Shipping/CountryCalcFactory.php new file mode 100644 index 0000000..673271f --- /dev/null +++ b/Shipping/CountryCalcFactory.php @@ -0,0 +1,54 @@ +getCountry()) + { + case Countries::PL: + $order_total = new OrderTotalPl(); + return new CalculationsBuilderPl($order, $order_total, $boxing_properties); + + case Countries::UK: + $order_total = new OrderTotalUk(); + return new CalculationsBuilderUk($order, $order_total, $boxing_properties); + + case Countries::US: + $order_total = new OrderTotalUs(); + return new CalculationsBuilderUs($order, $order_total, $boxing_properties); + + default: + $order_total = new OrderTotalWorld(); + return new CalculationsBuilderWorld($order, $order_total, $boxing_properties); + + } + } +} \ No newline at end of file diff --git a/Shipping/PriceFactory.php b/Shipping/PriceFactory.php new file mode 100644 index 0000000..82df66d --- /dev/null +++ b/Shipping/PriceFactory.php @@ -0,0 +1,31 @@ +getCountry(); - - switch($country) - { - case "PL": - $total = $order->getTotalPl(); - if($total > 100) - { - return '0PLN'; - } - //there will be more logic in the future - return '25PLN'; - - case "UK": - $total = $order->getTotalUk(); - - if($total > 300) - { - return '0'."GBP"; - } - //there will be more logic in the future - return '25'."GBP"; - case "US": - $total = $order->getTotalUs(); + $calc_factory = new CountryCalcFactory(); + $country_calculations_builder = $calc_factory->create($order, $boxing_properties); + $calculations_director = new CalculationsDirector($country_calculations_builder); - if($total > 1000) - { - return '$0'; - } - //there will be more logic in the future - return '$250'; - } + return $calculations_director->calculate(); } } \ No newline at end of file diff --git a/tests/MainTest.php b/tests/MainTest.php index 1ed41c1..724e4bb 100644 --- a/tests/MainTest.php +++ b/tests/MainTest.php @@ -1,52 +1,121 @@ start("PL", 50); + $result = $main->start(Countries::PL, 50); $this->assertEquals('25PLN', $result); } /** + * @feature Orders + * @sceanrio Calculate Shipping Cost + * @case to Poland with Client Shipping discount + * @test + */ + public function start_needToPayPLDiscount() + { + $main = new Main(); + $result = $main->start(Countries::PL, 50, 10); + + $this->assertEquals('15PLN', $result); + } + + /** + * @feature Orders + * @sceanrio Calculate Shipping Cost + * @case to Poland without Client Shipping discount and premium box + * @test + */ + public function start_needToPayPLDiscountANDPremiumBox() + { + $main = new Main(); + $result = $main->start(Countries::PL, 50, 10, 'PREMIUM_BOX'); + + $this->assertEquals('55PLN', $result); + } + + /** + * @feature Orders + * @sceanrio Calculate Shipping Cost + * @case to Poland free delivery above order total * @test */ public function start_freeShippingPL() { $main = new Main(); - $result = $main->start("PL", 150); + $result = $main->start(Countries::PL, 150); $this->assertEquals('0PLN', $result); } /** + * @feature Orders + * @sceanrio Calculate Shipping Cost + * @case to England free delivery above order total * @test */ public function start_freeShippingUK() { $main = new Main(); - $result = $main->start("UK", 450); + $result = $main->start(Countries::UK, 450); $this->assertEquals('0GBP', $result); } /** + * @feature Orders + * @sceanrio Calculate Shipping Cost + * @case to England free delivery above order total + * @test + */ + public function start_freeShippingUK_championsBox() + { + $main = new Main(); + $result = $main->start(Countries::UK, 450, 0, 'UEFA_CHAMPION'); + + $this->assertEquals('40GBP', $result); + } + + /** + * @feature Orders + * @sceanrio Calculate Shipping Cost + * @case to US free delivery above order total * @test */ public function start_freeShippingUs() { $main = new Main(); - $result = $main->start("US", 2450); + $result = $main->start(Countries::US, 2450); $this->assertEquals('$0', $result); } + + /** + * @feature Orders + * @sceanrio Calculate Shipping Cost + * @case to other countries - const delivery price in $ + * @test + */ + public function start_costForUnknowCountries() + { + $main = new Main(); + $result = $main->start(Countries::NIGERIA, 2450); + + $this->assertEquals('ETH299', $result); + } } \ No newline at end of file