Skip to content

Instantly share code, notes, and snippets.

@escapeboy
Created September 10, 2019 21:11
Show Gist options
  • Save escapeboy/e36fa6104f0807459f97762ac6d5e8f2 to your computer and use it in GitHub Desktop.
Save escapeboy/e36fa6104f0807459f97762ac6d5e8f2 to your computer and use it in GitHub Desktop.
POS Scanner
<?php
declare(strict_types=1);
namespace Src\PackItems;
final class Calculator
{
/**
* @var Item[]
*/
private $items;
/**
* @var array
*/
private $pricing;
private function __construct(array $items, array $pricing)
{
$this->items = $items;
$this->pricing = $pricing;
}
/**
* @return Calculator
*/
public static function empty(): Calculator
{
return new static([], []);
}
/**
* @param Item $item
*/
public function scan(Item $item): void
{
foreach ($this->items as $existingItem) {
if ($existingItem->equals($item)) {
$existingItem->setQuantity($existingItem->getQuantity() + $item->getQuantity());
return;
}
}
if(array_key_exists($item->getCode(), $this->pricing)){
$item->withPackPrice($this->pricing[$item->getCode()]);
}
$this->items[] = $item;
}
/**
* @return float
*/
public function total(): float
{
$total = 0;
foreach ($this->items as $item) {
$total += $item->getTotal();
}
return $total / 100;
}
/**
* @param array $pricing
*
* @return Calculator
*/
public function setPricing(array $pricing): Calculator
{
$this->pricing = $pricing;
return $this;
}
}
<?php
declare(strict_types=1);
namespace Src\PackItems;
final class Item
{
/**
* @var int
*/
private $price;
/**
* @var int
*/
private $quantity;
/**
* @var array
*/
private $packPrice;
/**
* @var string
*/
private $code;
private function __construct(string $code, int $price, int $quantity, array $packPrice)
{
$this->code = $code;
$this->price = $price;
$this->quantity = $quantity;
$this->packPrice = $packPrice;
}
/**
* @param string $code
* @param int $price
*
* @return Item
*/
public static function fromBasic(string $code, int $price)
{
return new static($code, $price, 1, []);
}
/**
* @return int
*/
public function getQuantity(): int
{
return $this->quantity;
}
/**
* @param Item $item
*
* @return bool
*/
public function equals(Item $item): bool
{
return $this->code === $item->getCode();
}
/**
* @return float
*/
public function getTotal(): float
{
if (!count($this->packPrice)) {
return $this->quantity * $this->price;
}
$packs = array_keys($this->packPrice);
$minPack = min($packs);
if ($this->quantity < $minPack) {
return $this->quantity * $this->price;
}
$totalPrice = 0;
$quantity = $this->quantity;
foreach ($this->packPrice as $packQuantity => $packPrice) {
if ($quantity < $packQuantity) {
break;
}
$totalPrice += $packQuantity * $packPrice;
$quantity -= $packQuantity;
}
$totalPrice += $quantity * $this->price;
return $totalPrice;
}
/**
* @return string
*/
public function getCode(): string
{
return $this->code;
}
/**
* @param int $quantity
*/
public function setQuantity(int $quantity): void
{
$this->quantity = $quantity;
}
/**
* @param array $packPrice
*
* @return Item
*/
public function withPackPrice(array $packPrice): Item
{
$this->packPrice = $packPrice;
return $this;
}
}
<?php
declare(strict_types=1);
namespace Tests\Unit;
use Src\PackItems\Calculator;
use Src\PackItems\Item;
use Tests\TestCase;
class PackItems extends TestCase
{
public function testFirst(){
$calculator = Calculator::empty()
->setPricing([
'A' => [4 => 175],
'C' => [6 => 100]
]);
$items = [
Item::fromBasic('A', 200),
Item::fromBasic('B', 1200),
Item::fromBasic('C', 125),
Item::fromBasic('D', 15),
Item::fromBasic('A', 200),
Item::fromBasic('B', 1200),
Item::fromBasic('A', 200),
Item::fromBasic('A', 200),
];
foreach($items as $item){
$calculator->scan($item);
}
$this->assertEquals(32.4, $calculator->total());
}
public function testSecond(){
$items = [
Item::fromBasic('C', 125),
Item::fromBasic('C', 125),
Item::fromBasic('C', 125),
Item::fromBasic('C', 125),
Item::fromBasic('C', 125),
Item::fromBasic('C', 125),
Item::fromBasic('C', 125),
];
$calculator = Calculator::empty()
->setPricing([
'C' => [6 => 100]
]);
foreach($items as $item){
$calculator->scan($item);
}
$this->assertEquals(7.25, $calculator->total());
}
public function testThird(){
$items = [
Item::fromBasic('A', 200),
Item::fromBasic('B', 1200),
Item::fromBasic('C', 125),
Item::fromBasic('D', 15),
];
$calculator = Calculator::empty()
->setPricing([
'A' => [4 => 175],
'C' => [6 => 100]
]);
foreach($items as $item){
$calculator->scan($item);
}
$this->assertEquals(15.4, $calculator->total());
}
public function testFourth()
{
$items = [
Item::fromBasic('A', 200),
Item::fromBasic('A', 200),
Item::fromBasic('A', 200),
Item::fromBasic('A', 200),
Item::fromBasic('A', 200),
];
$calculator = Calculator::empty()
->setPricing([
'A' => [4 => 175]
]);
foreach($items as $item){
$calculator->scan($item);
}
$this->assertEquals(((175*4) + 200) / 100, $calculator->total());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment