Skip to content

Commit

Permalink
Replaces array with Position class
Browse files Browse the repository at this point in the history
  • Loading branch information
MrKrisKrisu committed Aug 22, 2020
1 parent 7214c0b commit c68a08f
Show file tree
Hide file tree
Showing 5 changed files with 211 additions and 82 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ $ composer require mrkriskrisu/rewe-ereceipt-parser
```json
{
"require": {
"mrkriskrisu/rewe-ereceipt-parser": "^0.1"
"mrkriskrisu/rewe-ereceipt-parser": "^0.3"
}
}
```
Expand Down
8 changes: 8 additions & 0 deletions src/Exception/PositionNotFoundException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace REWEParser\Exception;

class PositionNotFoundException extends \Exception
{

}
118 changes: 118 additions & 0 deletions src/Position.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<?php

namespace REWEParser;

use REWEParser\Exception\ReceiptParseException;

class Position
{

private $name;
private $priceTotal;
private $priceSingle;
private $taxCode;

private $weight;
private $amount;

/**
* The name of the product.
* @return string|NULL
*/
public function getName()
{
return $this->name;
}

/**
* The total sum of the position
* @return float
* @throws ReceiptParseException
*/
public function getPriceTotal()
{
if ($this->priceTotal !== NULL)
return $this->priceTotal;
if ($this->priceSingle !== NULL && $this->amount !== NULL)
return $this->priceSingle * $this->amount;
if ($this->priceSingle !== NULL && $this->weight !== NULL)
return $this->priceSingle * $this->weight;
throw new ReceiptParseException();
}

/**
* The single value for one unit of the product
* @return float
* @throws ReceiptParseException
*/
public function getPriceSingle()
{
if ($this->priceSingle !== NULL)
return $this->priceSingle;
if ($this->priceTotal !== NULL && $this->amount !== NULL)
return $this->priceTotal / $this->amount;
if ($this->priceTotal !== NULL && $this->weight !== NULL)
return $this->priceTotal / $this->weight;
if ($this->priceTotal !== NULL)
return $this->priceTotal;
throw new ReceiptParseException();
}

/**
* The Tax Code of the position (e.g. "A" or "B")
* @return string|NULL
*/
public function getTaxCode()
{
return $this->taxCode;
}

/**
* The weight of the position (if the product is weightable)
* @return float|NULL
*/
public function getWeight()
{
return $this->weight;
}

/**
* The amount of the position (if the product is countable)
* @return int|NULL
*/
public function getAmount()
{
return $this->amount;
}

public function setName(string $name)
{
$this->name = $name;
}

public function setPriceTotal(string $priceTotal)
{
$this->priceTotal = $priceTotal;
}

public function setPriceSingle(string $priceSingle)
{
$this->priceSingle = $priceSingle;
}

public function setTaxCode(string $taxCode)
{
$this->taxCode = $taxCode;
}

public function setWeight(string $weight)
{
$this->weight = $weight;
}

public function setAmount(string $amount)
{
$this->amount = $amount;
}

}
112 changes: 61 additions & 51 deletions src/Receipt.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@
namespace REWEParser;

use Carbon\Carbon;
use REWEParser\Exception\PositionNotFoundException;
use REWEParser\Exception\ReceiptParseException;

class Receipt
{
private $raw_receipt;
private $expl_receipt;

function __construct(string $raw_receipt)
{
$this->raw_receipt = $raw_receipt;
$this->expl_receipt = explode("\n", $raw_receipt);
}

/**
Expand Down Expand Up @@ -149,6 +152,20 @@ private function getProductEndLine(): int
throw new ReceiptParseException();
}

/**
* @param string $name
* @return Position
* @throws PositionNotFoundException|ReceiptParseException
*/
public function getPositionByName(string $name): Position
{
foreach ($this->getPositions() as $position) {
if ($position->getName() == $name)
return $position;
}
throw new PositionNotFoundException("Position '$name' not found");
}

/**
* @return array
* @throws ReceiptParseException
Expand All @@ -157,74 +174,67 @@ public function getPositions(): array
{
$positions = [];

$startLine = $this->getProductStartLine();
$endLine = $this->getProductEndLine();

$rawPos = explode("\n", $this->raw_receipt);
$lastPos = NULL;
$lastPosition = NULL;

for ($lineNr = $startLine; $lineNr <= $endLine; $lineNr++) {
for ($lineNr = $this->getProductStartLine(); $lineNr <= $this->getProductEndLine(); $lineNr++) {
$line = trim($rawPos[$lineNr]);

if (strpos($line, ' Stk x') !== false && $lastPos != NULL) {
if ($this->isProductLine($lineNr)) {

if (preg_match('/(-?\d{1,}) Stk x *(-?\d{1,},\d{2})/', $line, $match)) {
$lastPos['amount'] = (int)$match[1];
$lastPos['price_single'] = (float)str_replace(',', '.', $match[2]);
if ($lastPosition !== NULL) {
$positions[] = $lastPosition;
$lastPosition = NULL;
}

} else if (strpos($line, 'kg') !== false && $lastPos != NULL) {
if (preg_match('/(.*) (-?\d{1,},\d{2}) (.{1})/', $line, $match)) {
$lastPosition = new Position();
$lastPosition->setName(trim($match[1]));
$lastPosition->setPriceTotal((float)str_replace(',', '.', $match[2]));
$lastPosition->setTaxCode($match[3]);
} else throw new ReceiptParseException("Error while parsing Product line");

if (preg_match('/(-?\d{1,},\d{3}) kg x *(-?\d{1,},\d{2}) EUR/', $line, $match)) {
$lastPos['weight'] = (float)str_replace(',', '.', $match[1]);
$lastPos['price_single'] = (float)str_replace(',', '.', $match[2]);
} else if (preg_match('/Handeingabe E-Bon *(-?\d{1,},\d{3}) kg/', $line, $match)) {
$lastPos['weight'] = (float)str_replace(',', '.', $match[1]);
}
} else if ($this->isAmountLine($lineNr)) {

} else {
if ($lastPos != NULL && isset($lastPos['name']) && isset($lastPos['price_total'])) {
if (!isset($lastPos['price_single']) && isset($lastPos['weight']))
$lastPos['price_single'] = $lastPos['price_total'] / $lastPos['weight'];
if (!isset($lastPos['price_single']) && isset($lastPos['amount']))
$lastPos['price_single'] = $lastPos['price_total'] / $lastPos['amount'];
if (!isset($lastPos['price_single'])) {
$lastPos['price_single'] = $lastPos['price_total'];
$lastPos['amount'] = 1;
}

$positions[] = $lastPos;
$lastPos = NULL;
}
if (preg_match('/(-?\d{1,}) Stk x *(-?\d{1,},\d{2})/', $line, $match)) {
$lastPosition->setAmount((int)$match[1]);
$lastPosition->setPriceSingle((float)str_replace(',', '.', $match[2]));
} else throw new ReceiptParseException("Error while parsing Amount line");

} else if ($this->isWeightLine($lineNr)) {

if (preg_match('/(.*) (-?\d{1,},\d{2}) (.{1})/', $line, $match)) {
$lastPos = [
'name' => trim($match[1]),
'price_total' => (float)str_replace(',', '.', $match[2]),
'tax_code' => $match[3]
];
}
if (preg_match('/(-?\d{1,},\d{3}) kg x *(-?\d{1,},\d{2}) EUR/', $line, $match)) {
$lastPosition->setWeight((float)str_replace(',', '.', $match[1]));
$lastPosition->setPriceSingle((float)str_replace(',', '.', $match[2]));
} else if (preg_match('/Handeingabe E-Bon *(-?\d{1,},\d{3}) kg/', $line, $match)) {
$lastPosition->setWeight((float)str_replace(',', '.', $match[1]));
} else throw new ReceiptParseException("Error while parsing Weight line");

}
}
} else throw new ReceiptParseException("Error while parsing unknown receipt line");

if ($lastPos != NULL && isset($lastPos['name']) && isset($lastPos['price_total'])) {
if (!isset($lastPos['price_single']) && isset($lastPos['weight']))
$lastPos['price_single'] = $lastPos['price_total'] / $lastPos['weight'];
if (!isset($lastPos['price_single']) && isset($lastPos['amount']))
$lastPos['price_single'] = $lastPos['price_total'] / $lastPos['amount'];
if (!isset($lastPos['price_single'])) {
$lastPos['price_single'] = $lastPos['price_total'];
$lastPos['amount'] = 1;
}
$positions[] = $lastPos;
$lastPos = NULL;
}

if ($lastPosition !== NULL)
$positions[] = $lastPosition;

if (count($positions) == 0)
throw new ReceiptParseException();
throw new ReceiptParseException("Cannot parse any products on receipt");

return $positions;
}

private function isWeightLine($lineNr)
{
return strpos($this->expl_receipt[$lineNr], 'kg') !== false;
}

private function isAmountLine($lineNr)
{
return strpos($this->expl_receipt[$lineNr], ' Stk x') !== false;
}

private function isProductLine($lineNr)
{
return !$this->isWeightLine($lineNr) && !$this->isAmountLine($lineNr);
}
}
53 changes: 23 additions & 30 deletions tests/ReceiptParsingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public function testNegativeTotalAmount(): void
/**
* @return void
* @throws \REWEParser\Exception\ReceiptParseException
* @throws \REWEParser\Exception\PositionNotFoundException
* @throws \Spatie\PdfToText\Exceptions\PdfNotFound
*/
public function testBonParsingWeight(): void
Expand All @@ -37,31 +38,27 @@ public function testBonParsingWeight(): void
$this->assertEquals(5, $receipt->getEarnedPaybackPoints());
$this->assertContains("EC-Cash", $receipt->getPaymentMethods());
$this->assertEquals(1577880000, $receipt->getTimestamp()->getTimestamp());

$positions = [];
foreach ($receipt->getPositions() as $position)
$positions[$position['name']] = $position;

$this->assertEquals(1, $positions['BROT']['price_single']);
$this->assertEquals(0.5, $positions['AUFSCHNITT']['price_single']);
$this->assertEquals(0.5, $positions['NATUR-JOGHURT']['price_single']);
$this->assertEquals(0.01, $positions['ESSEN']['price_single']);
$this->assertEquals(1.99, $positions['BANANE']['price_single']);
$this->assertEquals(2.99, $positions['BANANE']['price_total']);
$this->assertEquals(1.5, $positions['BANANE']['weight']);
$this->assertEquals(1, $positions['EIER']['price_single']);
$this->assertEquals(1, $positions['WEIZENMEHL']['price_single']);
$this->assertEquals(1, $positions['WASSER']['price_single']);
$this->assertEquals(1, $positions['SOFTDRINK']['price_single']);
$this->assertEquals(1, $positions['MILCH']['price_single']);
$this->assertEquals(1, $positions['EIS']['price_single']);
$this->assertEquals(1, $receipt->getPositionByName('BROT')->getPriceSingle());
$this->assertEquals(0.5, $receipt->getPositionByName('AUFSCHNITT')->getPriceSingle());
$this->assertEquals(0.5, $receipt->getPositionByName('NATUR-JOGHURT')->getPriceSingle());
$this->assertEquals(0.01, $receipt->getPositionByName('ESSEN')->getPriceSingle());
$this->assertEquals(1.99, $receipt->getPositionByName('BANANE')->getPriceSingle());
$this->assertEquals(2.99, $receipt->getPositionByName('BANANE')->getPriceTotal());
$this->assertEquals(1.5, $receipt->getPositionByName('BANANE')->getWeight());
$this->assertEquals(1, $receipt->getPositionByName('EIER')->getPriceSingle());
$this->assertEquals(1, $receipt->getPositionByName('WEIZENMEHL')->getPriceSingle());
$this->assertEquals(1, $receipt->getPositionByName('WASSER')->getPriceSingle());
$this->assertEquals(1, $receipt->getPositionByName('SOFTDRINK')->getPriceSingle());
$this->assertEquals(1, $receipt->getPositionByName('MILCH')->getPriceSingle());
$this->assertEquals(1, $receipt->getPositionByName('EIS')->getPriceSingle());

}

/**
* @return void
* @throws \REWEParser\Exception\ReceiptParseException
* @throws \Spatie\PdfToText\Exceptions\PdfNotFound
* @throws \REWEParser\Exception\PositionNotFoundException
*/
public function testBonParsingPaymentMethods(): void
{
Expand All @@ -77,18 +74,14 @@ public function testBonParsingPaymentMethods(): void
$this->assertContains("VISA", $receipt->getPaymentMethods());
$this->assertEquals(1577880000, $receipt->getTimestamp()->getTimestamp());

$positions = [];
foreach ($receipt->getPositions() as $position)
$positions[$position['name']] = $position;

$this->assertEquals(0.25, $positions['LEERGUT']['price_single']);
$this->assertEquals(2.99, $positions['KARTOFFELN']['price_single']);
$this->assertEquals(1.49, $positions['NUDELN']['price_single']);
$this->assertEquals(0.49, $positions['QUARK']['price_single']);
$this->assertEquals(1.99, $positions['SÜßIGKEITEN']['price_single']);
$this->assertEquals(0.69, $positions['SCHOKOLADE']['price_single']);
$this->assertEquals(1.38, $positions['SCHOKOLADE']['price_total']);
$this->assertEquals(0.53, $positions['SCHMAND 24%']['price_single']);
$this->assertEquals(0.25, $receipt->getPositionByName('LEERGUT')->getPriceSingle());
$this->assertEquals(2.99, $receipt->getPositionByName('KARTOFFELN')->getPriceSingle());
$this->assertEquals(1.49, $receipt->getPositionByName('NUDELN')->getPriceSingle());
$this->assertEquals(0.49, $receipt->getPositionByName('QUARK')->getPriceSingle());
$this->assertEquals(1.99, $receipt->getPositionByName('SÜßIGKEITEN')->getPriceSingle());
$this->assertEquals(0.69, $receipt->getPositionByName('SCHOKOLADE')->getPriceSingle());
$this->assertEquals(1.38, $receipt->getPositionByName('SCHOKOLADE')->getPriceTotal());
$this->assertEquals(0.53, $receipt->getPositionByName('SCHMAND 24%')->getPriceSingle());
}

/**
Expand Down

0 comments on commit c68a08f

Please sign in to comment.