diff --git a/Theme/Backend/purchase-bill-list.tpl.php b/Theme/Backend/purchase-bill-list.tpl.php
index 5db7e5c..ad3f775 100755
--- a/Theme/Backend/purchase-bill-list.tpl.php
+++ b/Theme/Backend/purchase-bill-list.tpl.php
@@ -42,6 +42,18 @@ echo $this->data['nav']->render(); ?>
+
= $this->getHtml('External'); ?>
+
+
+
| = $this->getHtml('Type'); ?>
| = $value->getNumber(); ?>
+ | = $value->external; ?>
| = $value->type->getL11n(); ?>
| = $value->supplier->number; ?>
| = $this->printHtml($value->billTo); ?>
@@ -170,7 +183,7 @@ echo $this->data['nav']->render(); ?>
| = $value->billZip; ?>
| = $value->billCity; ?>
| = $value->billCountry; ?>
- | = $this->getCurrency($value->netSales); ?>
+ | = $value->netSales->getAmount(); ?>
| = $value->createdAt->format('Y-m-d'); ?>
diff --git a/Theme/Backend/purchase-bill.tpl.php b/Theme/Backend/purchase-bill.tpl.php
index 5bd67ed..e9731e6 100755
--- a/Theme/Backend/purchase-bill.tpl.php
+++ b/Theme/Backend/purchase-bill.tpl.php
@@ -12,10 +12,17 @@
*/
declare(strict_types=1);
+use Modules\Billing\Models\BillStatus;
+use phpOMS\Localization\ISO3166NameEnum;
+use phpOMS\Localization\ISO3166TwoEnum;
+use phpOMS\Localization\ISO4217Enum;
+use phpOMS\Localization\ISO639Enum;
use phpOMS\Uri\UriFactory;
-// Media helper functions (e.g. file icon generator)
-include __DIR__ . '/../../../Media/Theme/Backend/template-functions.php';
+$countryCodes = ISO3166TwoEnum::getConstants();
+$countries = ISO3166NameEnum::getConstants();
+$languages = ISO639Enum::getConstants();
+$currencies = ISO4217Enum::getConstants();
/**
* @var \phpOMS\Views\View $this
@@ -27,24 +34,55 @@ $elements = $bill->elements;
$billTypes = $this->data['billtypes'] ?? [];
-$originalType = $this->data['originalType'];
-$original = $bill->getFileByType($originalType);
+$archive = $bill->getFileByTypeName('external');
/** @var \Modules\Auditor\Models\Audit */
$logs = $this->data['logs'] ?? [];
+$editable = $bill->id === 0 || \in_array($bill->status, [BillStatus::DRAFT, BillStatus::UNPARSED]);
+$disabled = $editable ? '' : ' disabled';
+
+$isNew = $archive->id === 0;
+
echo $this->data['nav']->render(); ?>
+isValid()) : ?>
+
+
+
+
+
+ areElementsValid()) : ?>
+ - = $this->getHtml('E_bill_items'); ?>
+
+ validateTaxAmountElements()) : ?>
+ - = $this->getHtml('E_bill_taxes'); ?>
+
+ validateNetElements()) : ?>
+ - = $this->getHtml('E_bill_net'); ?>
+
+ validateGrossElements()) : ?>
+ - = $this->getHtml('E_bill_gross'); ?>
+
+ validatePriceQuantityElements()) : ?>
+ - = $this->getHtml('E_bill_unit'); ?>
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
+
+
-
+
-
@@ -56,61 +94,148 @@ echo $this->data['nav']->render(); ?>
- = $this->getHtml('Invoice'); ?>
+ = $this->getHtml('Billing'); ?>
@@ -121,22 +246,42 @@ echo $this->data['nav']->render(); ?>
= $this->getHtml('Delivery'); ?>
@@ -147,56 +292,114 @@ echo $this->data['nav']->render(); ?>
-
+
= $this->getHtml('Invoice'); ?>download
-
+
-
+
+
+
+
+
+
@@ -208,7 +411,7 @@ echo $this->data['nav']->render(); ?>
@@ -225,66 +428,147 @@ echo $this->data['nav']->render(); ?>
+
-
+ status === BillStatus::DRAFT
+ || $bill->status === BillStatus::UNPARSED
+ || $bill->status === BillStatus::ACTIVE
+ ) : ?>
+
+
+
+
+
+
= $this->data['media-upload']->render('bill-file', 'files', '', $bill->files); ?>
+
@@ -295,8 +579,8 @@ echo $this->data['nav']->render(); ?>
| = $this->getHtml('ID', '0', '0'); ?>
- | = $this->getHtml('Trigger', 'Auditor', 'Backend'); ?>
| = $this->getHtml('Action', 'Auditor', 'Backend'); ?>
+ | = $this->getHtml('Trigger', 'Auditor', 'Backend'); ?>
| = $this->getHtml('CreatedBy', 'Auditor', 'Backend'); ?>
| = $this->getHtml('CreatedAt', 'Auditor', 'Backend'); ?>
|
@@ -306,22 +590,24 @@ echo $this->data['nav']->render(); ?>
?>
| = $audit->id; ?>
- | = $audit->trigger; ?>
| old === null) : echo $this->getHtml('CREATE', 'Auditor', 'Backend'); ?>
old !== null && $audit->new !== null) : echo $this->getHtml('UPDATE', 'Auditor', 'Backend'); ?>
new === null) : echo $this->getHtml('DELETE', 'Auditor', 'Backend'); ?>
getHtml('UNKNOWN', 'Auditor', 'Backend'); ?>
+ | = $audit->trigger; ?>
| = $this->printHtml(
$this->renderUserName('%3$s %2$s %1$s', [$audit->createdBy->name1, $audit->createdBy->name2, $audit->createdBy->name3, $audit->createdBy->login])
); ?>
- | = $audit->createdAt->format('Y-m-d'); ?>
+ | = $audit->createdAt->format('Y-m-d H:i'); ?>
|
+
+
diff --git a/Theme/Backend/user-purchase-bill-dashboard.tpl.php b/Theme/Backend/user-purchase-bill-dashboard.tpl.php
index 2bc9062..176c8b3 100755
--- a/Theme/Backend/user-purchase-bill-dashboard.tpl.php
+++ b/Theme/Backend/user-purchase-bill-dashboard.tpl.php
@@ -44,6 +44,18 @@ echo $this->data['nav']->render(); ?>
+ = $this->getHtml('External'); ?>
+
+
+
| = $this->getHtml('Type'); ?>
| = $value->getNumber(); ?>
+ | = $value->external; ?>
| = $value->type->getL11n(); ?>
| = $value->supplier->number; ?>
| = $this->printHtml($value->billTo); ?>
@@ -176,7 +189,7 @@ echo $this->data['nav']->render(); ?>
: ISO3166NameEnum::getByName(
ISO3166TwoEnum::getName($value->billCountry)
); ?>
- | = $value->grossCosts->getAmount(); ?>
+ | = $value->grossSales->getAmount(); ?>
| = $value->billDate?->format('Y-m-d'); ?>
diff --git a/Theme/Backend/user-purchase-bill.tpl.php b/Theme/Backend/user-purchase-bill.tpl.php
deleted file mode 100755
index c32abe0..0000000
--- a/Theme/Backend/user-purchase-bill.tpl.php
+++ /dev/null
@@ -1,350 +0,0 @@
-data['bill'];
-$elements = $bill->elements;
-
-$previewType = $this->data['previewType'];
-$originalType = $this->data['originalType'];
-$billPdf = $bill->getFileByType($previewType);
-$original = $bill->getFileByType($originalType);
-$media = $bill->files;
-
-echo $this->data['nav']->render(); ?>
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- = $this->getHtml('Invoice'); ?>
-
-
-
-
-
-
- = $this->getHtml('Delivery'); ?>
-
-
-
-
-
-
-
-
-
-
- = $this->getHtml('Invoice'); ?>download
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- = $this->getHtml('Payment'); ?>
-
-
-
-
-
-
-
-
-
-
- = $this->getHtml('Media'); ?>
-
-
-
-
-
-
-
- = $this->getHtml('Media'); ?>download
-
-
-
- |
- |
- | = $this->getHtml('Name'); ?>
- | = $this->getHtml('Type'); ?>
- |
- extension === 'collection'
- ? UriFactory::build('{/base}/media/list?path=' . \rtrim($file->getVirtualPath(), '/') . '/' . $file->name)
- : UriFactory::build('{/base}/media/view?id=' . $file->id
- . '&path={?path}' . (
- $file->id === 0
- ? '/' . $file->name
- : ''
- )
- );
-
- $icon = $fileIconFunction(FileUtils::getExtensionType($file->extension));
- ?>
-
- |
- | = $this->printHtml($icon); ?>
- | = $file->name; ?>
- | = $file->extension; ?>
-
- |
-
-
-
-
-
-
-
-
-
-
- = $this->getHtml('Logs'); ?>download
-
-
- | IP
- | = $this->getHtml('ID', '0', '0'); ?>
- | = $this->getHtml('Name'); ?>
- | = $this->getHtml('Log'); ?>
- | = $this->getHtml('Date'); ?>
- |
-
- | = $this->printHtml($this->request->getOrigin()); ?>
- | = $this->printHtml((string) $this->request->header->account); ?>
- | = $this->printHtml((string) $this->request->header->account); ?>
- | Create Invoice
- | = $this->printHtml((new \DateTime('now'))->format('Y-m-d H:i:s')); ?>
- |
-
-
-
-
-
-
-
diff --git a/tests/Autoloader.php b/tests/Autoloader.php
index 561d764..28b8056 100755
--- a/tests/Autoloader.php
+++ b/tests/Autoloader.php
@@ -36,6 +36,7 @@ final class Autoloader
__DIR__ . '/../',
__DIR__ . '/../MainRepository/',
__DIR__ . '/../../',
+ __DIR__ . '/../../../',
];
/**
diff --git a/tests/Models/InvoiceRecognitionTest.php b/tests/Models/InvoiceRecognitionTest.php
new file mode 100644
index 0000000..c593c45
--- /dev/null
+++ b/tests/Models/InvoiceRecognitionTest.php
@@ -0,0 +1,352 @@
+netSales->value);
+ }
+
+ /**
+ * @dataProvider billList
+ */
+ public function testTaxRate($json, $content) : void
+ {
+ $billObj = new Bill();
+ InvoiceRecognition::detect($billObj, $content);
+
+ $test = \json_decode(\file_get_contents($json), true);
+
+ self::assertEquals($test['tax_rate'], \reset($billObj->elements)->taxR->value);
+ }
+
+ /**
+ * @dataProvider billList
+ */
+ public function testGrossSales($json, $content) : void
+ {
+ $billObj = new Bill();
+ InvoiceRecognition::detect($billObj, $content);
+
+ $test = \json_decode(\file_get_contents($json), true);
+
+ self::assertEquals($test['grossSales'], $billObj->grossSales->value);
+ }
+
+ /**
+ * @dataProvider billList
+ */
+ public function testTaxAmount($json, $content) : void
+ {
+ $billObj = new Bill();
+ InvoiceRecognition::detect($billObj, $content);
+
+ $test = \json_decode(\file_get_contents($json), true);
+
+ self::assertEquals($test['tax_amount'], $billObj->taxP->value);
+ }
+
+ /**
+ * @dataProvider billList
+ */
+ public function testBillDate($json, $content) : void
+ {
+ $billObj = new Bill();
+ InvoiceRecognition::detect($billObj, $content);
+
+ $test = \json_decode(\file_get_contents($json), true);
+
+ self::assertEquals($test['bill_date'], $billObj->billDate?->format('Y-m-d'));
+ }
+
+ /**
+ * @dataProvider billList
+ */
+ public function testBillLanguage($json, $content) : void
+ {
+ $billObj = new Bill();
+ InvoiceRecognition::detect($billObj, $content);
+
+ $test = \json_decode(\file_get_contents($json), true);
+
+ self::assertEquals($test['language'], $billObj->language);
+ }
+
+ /**
+ * @dataProvider billList
+ */
+ public function testBillCurrency($json, $content) : void
+ {
+ $billObj = new Bill();
+ InvoiceRecognition::detect($billObj, $content);
+
+ $test = \json_decode(\file_get_contents($json), true);
+
+ self::assertEquals($test['currency'], $billObj->currency);
+ }
+
+ /**
+ * @dataProvider billList
+ */
+ public function testIban($json, $content) : void
+ {
+ $identifierContent = \file_get_contents(__DIR__ . '/../../Models/bill_identifier.json');
+ if ($identifierContent === false) {
+ $identifierContent = '{}';
+ }
+
+ /** @var array $identifiers */
+ $identifiers = \json_decode($identifierContent, true);
+
+ $test = \json_decode(\file_get_contents($json), true);
+
+ $lines = \explode("\n", $content);
+ foreach ($lines as $line => $value) {
+ if (empty(\trim($value))) {
+ unset($lines[$line]);
+ }
+ }
+ $lines = \array_values($lines);
+
+ self::assertEquals(
+ \str_replace(' ', '', $test['iban']),
+ \str_replace(' ', '', InvoiceRecognition::findIban($lines, $identifiers['iban']))
+ );
+ }
+
+ /**
+ * @dataProvider billList
+ */
+ public function testVATId($json, $content) : void
+ {
+ $identifierContent = \file_get_contents(__DIR__ . '/../../Models/bill_identifier.json');
+ if ($identifierContent === false) {
+ $identifierContent = '{}';
+ }
+
+ /** @var array $identifiers */
+ $identifiers = \json_decode($identifierContent, true);
+
+ $test = \json_decode(\file_get_contents($json), true);
+
+ $lines = \explode("\n", $content);
+ foreach ($lines as $line => $value) {
+ if (empty(\trim($value))) {
+ unset($lines[$line]);
+ }
+ }
+ $lines = \array_values($lines);
+
+ self::assertEquals(
+ $test['vat_id'],
+ InvoiceRecognition::findVat($lines, $identifiers['vat_id'][$test['language']])
+ );
+ }
+
+ /**
+ * @dataProvider billList
+ */
+ public function testTaxId($json, $content) : void
+ {
+ $identifierContent = \file_get_contents(__DIR__ . '/../../Models/bill_identifier.json');
+ if ($identifierContent === false) {
+ $identifierContent = '{}';
+ }
+
+ /** @var array $identifiers */
+ $identifiers = \json_decode($identifierContent, true);
+
+ $test = \json_decode(\file_get_contents($json), true);
+
+ $lines = \explode("\n", $content);
+ foreach ($lines as $line => $value) {
+ if (empty(\trim($value))) {
+ unset($lines[$line]);
+ }
+ }
+ $lines = \array_values($lines);
+
+ self::assertEquals(
+ $test['tax_id'],
+ InvoiceRecognition::findTaxId($lines, $identifiers['tax_id'][$test['language']])
+ );
+ }
+
+ /**
+ * @dataProvider billList
+ */
+ public function testWebsite($json, $content) : void
+ {
+ $identifierContent = \file_get_contents(__DIR__ . '/../../Models/bill_identifier.json');
+ if ($identifierContent === false) {
+ $identifierContent = '{}';
+ }
+
+ /** @var array $identifiers */
+ $identifiers = \json_decode($identifierContent, true);
+
+ $test = \json_decode(\file_get_contents($json), true);
+
+ $lines = \explode("\n", $content);
+ foreach ($lines as $line => $value) {
+ if (empty(\trim($value))) {
+ unset($lines[$line]);
+ }
+ }
+ $lines = \array_values($lines);
+
+ self::assertEquals(
+ $test['website'],
+ InvoiceRecognition::findWebsite($lines, $identifiers['website'])
+ );
+ }
+
+ /**
+ * @dataProvider billList
+ */
+ public function testEmail($json, $content) : void
+ {
+ $identifierContent = \file_get_contents(__DIR__ . '/../../Models/bill_identifier.json');
+ if ($identifierContent === false) {
+ $identifierContent = '{}';
+ }
+
+ /** @var array $identifiers */
+ $identifiers = \json_decode($identifierContent, true);
+
+ $test = \json_decode(\file_get_contents($json), true);
+
+ $lines = \explode("\n", $content);
+ foreach ($lines as $line => $value) {
+ if (empty(\trim($value))) {
+ unset($lines[$line]);
+ }
+ }
+ $lines = \array_values($lines);
+
+ self::assertEquals(
+ $test['email'],
+ InvoiceRecognition::findEmail($lines, $identifiers['email'])
+ );
+ }
+
+ /**
+ * @dataProvider billList
+ */
+ public function testPhone($json, $content) : void
+ {
+ $identifierContent = \file_get_contents(__DIR__ . '/../../Models/bill_identifier.json');
+ if ($identifierContent === false) {
+ $identifierContent = '{}';
+ }
+
+ /** @var array $identifiers */
+ $identifiers = \json_decode($identifierContent, true);
+
+ $test = \json_decode(\file_get_contents($json), true);
+
+ $lines = \explode("\n", $content);
+ foreach ($lines as $line => $value) {
+ if (empty(\trim($value))) {
+ unset($lines[$line]);
+ }
+ }
+ $lines = \array_values($lines);
+
+ self::assertEquals(
+ \str_replace(' ', '', $test['phone']),
+ \str_replace(' ', '', InvoiceRecognition::findPhone($lines, $identifiers['phone'][$test['language']]))
+ );
+ }
+
+ public static array $billList = [];
+
+ public function billList()
+ {
+ /*
+ if (\str_ends_with(__DIR__ . '/bills/12.png', 'pdf')) {
+ $content = PdfParser::pdf2text(__DIR__ . '/bills/12.png');
+ } else {
+ $ocr = new TesseractOcr();
+
+ $content = $ocr->parseImage(__DIR__ . '/bills/12.png');
+ }
+
+ return [
+ [
+ __DIR__ . '/bills/12.json',
+ $content
+ ]
+ ];
+ */
+
+ if (!empty(self::$billList)) {
+ return self::$billList;
+ }
+
+ $files = \scandir(__DIR__ . '/bills/');
+ foreach ($files as $bill) {
+ if ($bill === '.' || $bill === '..' || \str_ends_with($bill, '.json')) {
+ continue;
+ }
+
+ $parts = \explode('.', $bill);
+ $count = \count($parts);
+ unset($parts[$count - 1]);
+
+ if (\str_ends_with(__DIR__ . '/bills/' . $bill, 'pdf')) {
+ $content = PdfParser::pdf2text(__DIR__ . '/bills/' . $bill);
+ } else {
+ $ocr = new TesseractOcr();
+
+ $content = $ocr->parseImage(__DIR__ . '/bills/' . $bill);
+ }
+
+ $element = [
+ __DIR__ . '/bills/' . \implode('', $parts) . '.json',
+ $content
+ ];
+
+ self::$billList[] = $element;
+ }
+
+ return self::$billList;
+ }
+
+ public static function tearDownAfterClass() : void
+ {
+ self::$billList = [];
+ }
+}
diff --git a/tests/Models/bills/1.json b/tests/Models/bills/1.json
new file mode 100644
index 0000000..9ef8af5
--- /dev/null
+++ b/tests/Models/bills/1.json
@@ -0,0 +1,34 @@
+{
+ "invoice_number": "20191242",
+ "grossSales": 2800000,
+ "netSales": 2800000,
+ "tax_amount": 0,
+ "tax_rate": 0,
+ "bill_date": "2019-09-12",
+ "delivery_date": "",
+ "due_date": "2019-09-12",
+ "vat_id": "DE12345678",
+ "tax_id": "12/112233/44221",
+ "address": {
+ "name": "fortytools gmbh",
+ "address": "Georgsplatz 10",
+ "city": "20099 Hamburg",
+ "country": ""
+ },
+ "iban": "",
+ "elements": [
+ {
+ "position": 1,
+ "description": "",
+ "quantity": 10000,
+ "unit": "pro Woche",
+ "price": 280000,
+ "total": 280000
+ }
+ ],
+ "language": "de",
+ "currency": "EUR",
+ "email": "info@fortytools-cleaning.com",
+ "website": "",
+ "phone": "+49-40-609 407 89 - 0"
+}
\ No newline at end of file
diff --git a/tests/Models/bills/1.png b/tests/Models/bills/1.png
new file mode 100644
index 0000000..954323b
Binary files /dev/null and b/tests/Models/bills/1.png differ
diff --git a/tests/Models/bills/10.json b/tests/Models/bills/10.json
new file mode 100644
index 0000000..7791aff
--- /dev/null
+++ b/tests/Models/bills/10.json
@@ -0,0 +1,26 @@
+{
+ "invoice_number": "12345",
+ "grossSales": 11200000,
+ "netSales": 11200000,
+ "tax_amount": 0,
+ "tax_rate": 0,
+ "bill_date": "",
+ "delivery_date": "",
+ "service_date": "",
+ "due_date": "",
+ "vat_id": "",
+ "tax_id": "",
+ "address": {
+ "name": "",
+ "address": "",
+ "city": "",
+ "country": ""
+ },
+ "iban": "DE34233004333401",
+ "elements": [],
+ "language": "de",
+ "currency": "EUR",
+ "email": "mail@musterfirma.com",
+ "website": "www.musterfirma.com",
+ "phone": "(+49) 1234/98 76 54"
+}
\ No newline at end of file
diff --git a/tests/Models/bills/10.png b/tests/Models/bills/10.png
new file mode 100644
index 0000000..ae903d6
Binary files /dev/null and b/tests/Models/bills/10.png differ
diff --git a/tests/Models/bills/11.jpg b/tests/Models/bills/11.jpg
new file mode 100644
index 0000000..79ab0a9
Binary files /dev/null and b/tests/Models/bills/11.jpg differ
diff --git a/tests/Models/bills/11.json b/tests/Models/bills/11.json
new file mode 100644
index 0000000..b99ea4a
--- /dev/null
+++ b/tests/Models/bills/11.json
@@ -0,0 +1,26 @@
+{
+ "invoice_number": "",
+ "grossSales": 20440000,
+ "netSales": 0,
+ "tax_amount": 0,
+ "tax_rate": 0,
+ "bill_date": "",
+ "delivery_date": "",
+ "service_date": "",
+ "due_date": "",
+ "vat_id": "",
+ "tax_id": "",
+ "address": {
+ "name": "",
+ "address": "",
+ "city": "",
+ "country": ""
+ },
+ "iban": "",
+ "elements": [],
+ "language": "de",
+ "currency": "EUR",
+ "email": "",
+ "website": "",
+ "phone": ""
+}
\ No newline at end of file
diff --git a/tests/Models/bills/12.json b/tests/Models/bills/12.json
new file mode 100644
index 0000000..7525ebd
--- /dev/null
+++ b/tests/Models/bills/12.json
@@ -0,0 +1,26 @@
+{
+ "invoice_number": "10005",
+ "grossSales": 1160000,
+ "netSales": 1000000,
+ "tax_amount": 160000,
+ "tax_rate": 160000,
+ "bill_date": "2020-09-22",
+ "delivery_date": "",
+ "service_date": "",
+ "due_date": "",
+ "vat_id": "DE814878557",
+ "tax_id": "122/5719/4368",
+ "address": {
+ "name": "easzbill GmbH",
+ "address": "Düsselstr. 21",
+ "city": "41564 Kaarst",
+ "country": ""
+ },
+ "iban": "DE58300700240509944500",
+ "elements": [],
+ "language": "de",
+ "currency": "EUR",
+ "email": "support@easybill.de",
+ "website": "www.easybil.de",
+ "phone": "+49 2154 897 01 - 20"
+}
\ No newline at end of file
diff --git a/tests/Models/bills/12.png b/tests/Models/bills/12.png
new file mode 100644
index 0000000..e231802
Binary files /dev/null and b/tests/Models/bills/12.png differ
diff --git a/tests/Models/bills/14.json b/tests/Models/bills/14.json
new file mode 100644
index 0000000..91d1784
--- /dev/null
+++ b/tests/Models/bills/14.json
@@ -0,0 +1,26 @@
+{
+ "invoice_number": "2021011",
+ "grossSales": 15969800,
+ "netSales": 13420000,
+ "tax_amount": 2549800,
+ "tax_rate": 190000,
+ "bill_date": "2021-03-29",
+ "delivery_date": "",
+ "service_date": "",
+ "due_date": "2021-04-28",
+ "vat_id": "DE234567891",
+ "tax_id": "",
+ "address": {
+ "name": "Invoice Office GmbH",
+ "address": "Inge-Meysel Str. 8a",
+ "city": "85053 Ingolstadt",
+ "country": ""
+ },
+ "iban": "DE20000111122223332103",
+ "elements": [],
+ "language": "de",
+ "currency": "EUR",
+ "email": "demo@invoiceoffice.de",
+ "website": "",
+ "phone": "0049123456789"
+}
\ No newline at end of file
diff --git a/tests/Models/bills/14.png b/tests/Models/bills/14.png
new file mode 100644
index 0000000..571dcc6
Binary files /dev/null and b/tests/Models/bills/14.png differ
diff --git a/tests/Models/bills/15.json b/tests/Models/bills/15.json
new file mode 100644
index 0000000..f504363
--- /dev/null
+++ b/tests/Models/bills/15.json
@@ -0,0 +1,26 @@
+{
+ "invoice_number": "2021012",
+ "grossSales": 92391600,
+ "netSales": 77640000,
+ "tax_amount": 14751600,
+ "tax_rate": 190000,
+ "bill_date": "2021-03-29",
+ "delivery_date": "",
+ "service_date": "",
+ "due_date": "2021-04-28",
+ "vat_id": "DE123456789",
+ "tax_id": "",
+ "address": {
+ "name": "Invoice Office GmbH",
+ "address": "Inge-Meysel Str. 8a",
+ "city": "85053 Ingolstadt",
+ "country": ""
+ },
+ "iban": "DE20000111122223332103",
+ "elements": [],
+ "language": "de",
+ "currency": "EUR",
+ "email": "demo@invoiceoffice.de",
+ "website": "",
+ "phone": "0049123456789"
+}
\ No newline at end of file
diff --git a/tests/Models/bills/15.png b/tests/Models/bills/15.png
new file mode 100644
index 0000000..f07c49d
Binary files /dev/null and b/tests/Models/bills/15.png differ
diff --git a/tests/Models/bills/16.json b/tests/Models/bills/16.json
new file mode 100644
index 0000000..9bfc568
--- /dev/null
+++ b/tests/Models/bills/16.json
@@ -0,0 +1,26 @@
+{
+ "invoice_number": "1001",
+ "grossSales": 4658900,
+ "netSales": 3915000,
+ "tax_amount": 743900,
+ "tax_rate": 190000,
+ "bill_date": "2021-02-17",
+ "delivery_date": "",
+ "service_date": "",
+ "due_date": "",
+ "vat_id": "",
+ "tax_id": "",
+ "address": {
+ "name": "Ihre Firma",
+ "address": "Musterstraße X",
+ "city": "12345 Musterstadt",
+ "country": ""
+ },
+ "iban": "DE85123456789012345678",
+ "elements": [],
+ "language": "de",
+ "currency": "EUR",
+ "email": "firmaxyz@gmail.de",
+ "website": "www.firmaxyz.de",
+ "phone": "+49 1234/12 34 56"
+}
\ No newline at end of file
diff --git a/tests/Models/bills/16.png b/tests/Models/bills/16.png
new file mode 100644
index 0000000..c234834
Binary files /dev/null and b/tests/Models/bills/16.png differ
diff --git a/tests/Models/bills/17.json b/tests/Models/bills/17.json
new file mode 100644
index 0000000..3cc29b2
--- /dev/null
+++ b/tests/Models/bills/17.json
@@ -0,0 +1,26 @@
+{
+ "invoice_number": "DE-001",
+ "grossSales": 1654100,
+ "netSales": 1390000,
+ "tax_amount": 264100,
+ "tax_rate": 190000,
+ "bill_date": "2019-01-29",
+ "delivery_date": "",
+ "service_date": "",
+ "due_date": "2019-01-29",
+ "vat_id": "",
+ "tax_id": "",
+ "address": {
+ "name": "European Auto Parts",
+ "address": "Schillingbrücke 58",
+ "city": "73111 Berlin",
+ "country": ""
+ },
+ "iban": "DE9112345678",
+ "elements": [],
+ "language": "de",
+ "currency": "EUR",
+ "email": "",
+ "website": "",
+ "phone": ""
+}
\ No newline at end of file
diff --git a/tests/Models/bills/17.png b/tests/Models/bills/17.png
new file mode 100644
index 0000000..dd8bd25
Binary files /dev/null and b/tests/Models/bills/17.png differ
diff --git a/tests/Models/bills/18.jpg b/tests/Models/bills/18.jpg
new file mode 100644
index 0000000..6419779
Binary files /dev/null and b/tests/Models/bills/18.jpg differ
diff --git a/tests/Models/bills/18.json b/tests/Models/bills/18.json
new file mode 100644
index 0000000..2fadccc
--- /dev/null
+++ b/tests/Models/bills/18.json
@@ -0,0 +1,26 @@
+{
+ "invoice_number": "1234",
+ "grossSales": 36533000,
+ "netSales": 30700000,
+ "tax_amount": 5833000,
+ "tax_rate": 190000,
+ "bill_date": "2020-01-01",
+ "delivery_date": "",
+ "service_date": "",
+ "due_date": "",
+ "vat_id": "DE123456789",
+ "tax_id": "",
+ "address": {
+ "name": "pixa",
+ "address": "Musterstraße 1",
+ "city": "12345 Berlin",
+ "country": ""
+ },
+ "iban": "DE07123412341234123412",
+ "elements": [],
+ "language": "de",
+ "currency": "EUR",
+ "email": "mail@example.com",
+ "website": "",
+ "phone": "+49 123 456789"
+}
\ No newline at end of file
diff --git a/tests/Models/bills/19.json b/tests/Models/bills/19.json
new file mode 100644
index 0000000..a841dbf
--- /dev/null
+++ b/tests/Models/bills/19.json
@@ -0,0 +1,26 @@
+{
+ "invoice_number": "2019-1001",
+ "grossSales": 357000,
+ "netSales": 300000,
+ "tax_amount": 57000,
+ "tax_rate": 190000,
+ "bill_date": "2019-01-01",
+ "delivery_date": "",
+ "service_date": "",
+ "due_date": "",
+ "vat_id": "DE24324567",
+ "tax_id": "",
+ "address": {
+ "name": "Musterfirma GmbH",
+ "address": "Musterstraße 23",
+ "city": "12345 Musterhausen",
+ "country": ""
+ },
+ "iban": "DE3423456234356765",
+ "elements": [],
+ "language": "de",
+ "currency": "EUR",
+ "email": "info@muster.de",
+ "website": "www.firma.de",
+ "phone": "+40 (0)30 12345678"
+}
\ No newline at end of file
diff --git a/tests/Models/bills/19.png b/tests/Models/bills/19.png
new file mode 100644
index 0000000..a620d69
Binary files /dev/null and b/tests/Models/bills/19.png differ
diff --git a/tests/Models/bills/2.json b/tests/Models/bills/2.json
new file mode 100644
index 0000000..93d22cd
--- /dev/null
+++ b/tests/Models/bills/2.json
@@ -0,0 +1,26 @@
+{
+ "invoice_number": "12345",
+ "grossSales": 16838500,
+ "netSales": 14150000,
+ "tax_amount": 2688500,
+ "tax_rate": 190000,
+ "bill_date": "2022-01-01",
+ "delivery_date": "",
+ "service_date": "",
+ "due_date": "2022-01-15",
+ "vat_id": "",
+ "tax_id": "123456789",
+ "address": {
+ "name": "Vorname Name",
+ "address": "Musterstraße 123",
+ "city": "12345 Musterstadt",
+ "country": ""
+ },
+ "iban": "",
+ "elements": [],
+ "language": "de",
+ "currency": "EUR",
+ "email": "hallo@superduperseite.de",
+ "website": "www.superduperseite.de",
+ "phone": ""
+}
\ No newline at end of file
diff --git a/tests/Models/bills/2.png b/tests/Models/bills/2.png
new file mode 100644
index 0000000..d68b7ff
Binary files /dev/null and b/tests/Models/bills/2.png differ
diff --git a/tests/Models/bills/3.json b/tests/Models/bills/3.json
new file mode 100644
index 0000000..70eb5b1
--- /dev/null
+++ b/tests/Models/bills/3.json
@@ -0,0 +1,26 @@
+{
+ "invoice_number": "01234",
+ "grossSales": 21420000,
+ "netSales": 18000000,
+ "tax_amount": 3420000,
+ "tax_rate": 190000,
+ "bill_date": "2024-08-13",
+ "delivery_date": "",
+ "service_date": "",
+ "due_date": "2024-09-15",
+ "vat_id": "",
+ "tax_id": "0123 4567 8901",
+ "address": {
+ "name": "Werbeagentur Kluger",
+ "address": "Jede Straße 123",
+ "city": "12345 Jede Stadt",
+ "country": ""
+ },
+ "iban": "",
+ "elements": [],
+ "language": "de",
+ "currency": "EUR",
+ "email": "hallo@superduperseite.de",
+ "website": "",
+ "phone": "(0221) 1234-56"
+}
\ No newline at end of file
diff --git a/tests/Models/bills/3.png b/tests/Models/bills/3.png
new file mode 100644
index 0000000..5a5abd0
Binary files /dev/null and b/tests/Models/bills/3.png differ
diff --git a/tests/Models/bills/4.json b/tests/Models/bills/4.json
new file mode 100644
index 0000000..fe80f85
--- /dev/null
+++ b/tests/Models/bills/4.json
@@ -0,0 +1,26 @@
+{
+ "invoice_number": "2021021",
+ "grossSales": 15113000,
+ "netSales": 12700000,
+ "tax_amount": 2413000,
+ "tax_rate": 190000,
+ "bill_date": "2021-04-01",
+ "delivery_date": "",
+ "service_date": "",
+ "due_date": "2021-05-01",
+ "vat_id": "DE123456789",
+ "tax_id": "",
+ "address": {
+ "name": "Invoice Office GmbH",
+ "address": "Inge-Mezsel Str. 8a",
+ "city": "85053 Ingolstadt",
+ "country": ""
+ },
+ "iban": "DE20000111122223332103",
+ "elements": [],
+ "language": "de",
+ "currency": "EUR",
+ "email": "demo@invoiceoffice.de",
+ "website": "",
+ "phone": "0049123456789"
+}
\ No newline at end of file
diff --git a/tests/Models/bills/4.png b/tests/Models/bills/4.png
new file mode 100644
index 0000000..44abfa9
Binary files /dev/null and b/tests/Models/bills/4.png differ
diff --git a/tests/Models/bills/5.json b/tests/Models/bills/5.json
new file mode 100644
index 0000000..67205eb
--- /dev/null
+++ b/tests/Models/bills/5.json
@@ -0,0 +1,26 @@
+{
+ "invoice_number": "323525",
+ "grossSales": 7809300,
+ "netSales": 6562400,
+ "tax_amount": 1246900,
+ "tax_rate": 190000,
+ "bill_date": "2022-08-10",
+ "delivery_date": "",
+ "service_date": "",
+ "due_date": "",
+ "vat_id": "DE101778899",
+ "tax_id": "200/100/10001",
+ "address": {
+ "name": "Handwerker Muster",
+ "address": "Musterstraße 1",
+ "city": "123456 Musterstadt",
+ "country": ""
+ },
+ "iban": "DE02345611110000100020",
+ "elements": [],
+ "language": "de",
+ "currency": "EUR",
+ "email": "",
+ "website": "",
+ "phone": "+49 123 456 789-0"
+}
\ No newline at end of file
diff --git a/tests/Models/bills/5.png b/tests/Models/bills/5.png
new file mode 100644
index 0000000..e45d2b6
Binary files /dev/null and b/tests/Models/bills/5.png differ
diff --git a/tests/Models/bills/6.json b/tests/Models/bills/6.json
new file mode 100644
index 0000000..e5974c6
--- /dev/null
+++ b/tests/Models/bills/6.json
@@ -0,0 +1,26 @@
+{
+ "invoice_number": "2021010",
+ "grossSales": 22848000,
+ "netSales": 19200000,
+ "tax_amount": 3648000,
+ "tax_rate": 190000,
+ "bill_date": "2021-03-29",
+ "delivery_date": "",
+ "service_date": "",
+ "due_date": "2021-04-28",
+ "vat_id": "DE123456789",
+ "tax_id": "",
+ "address": {
+ "name": "Invoice Office GmbH",
+ "address": "Inge-Meysel Str. 8a",
+ "city": "85053 Ingolstadt",
+ "country": ""
+ },
+ "iban": "DE20000111122223332103",
+ "elements": [],
+ "language": "de",
+ "currency": "EUR",
+ "email": "demo@invoiceoffice.de",
+ "website": "",
+ "phone": "0049123456789"
+}
\ No newline at end of file
diff --git a/tests/Models/bills/6.png b/tests/Models/bills/6.png
new file mode 100644
index 0000000..880b739
Binary files /dev/null and b/tests/Models/bills/6.png differ
diff --git a/tests/Models/bills/7.json b/tests/Models/bills/7.json
new file mode 100644
index 0000000..80f9d0c
--- /dev/null
+++ b/tests/Models/bills/7.json
@@ -0,0 +1,26 @@
+{
+ "invoice_number": "220002",
+ "grossSales": 6021400,
+ "netSales": 5060000,
+ "tax_amount": 961400,
+ "tax_rate": 190000,
+ "bill_date": "2022-11-04",
+ "delivery_date": "",
+ "service_date": "",
+ "due_date": "2022-11-18",
+ "vat_id": "",
+ "tax_id": "45/123/12345",
+ "address": {
+ "name": "Handwerksmeister Frity Blau",
+ "address": "Musterstraße 123",
+ "city": "12345 Berlin",
+ "country": ""
+ },
+ "iban": "DE100023145678",
+ "elements": [],
+ "language": "de",
+ "currency": "EUR",
+ "email": "info@mustermann.de",
+ "website": "www.mustermann.de",
+ "phone": "+49 (30) 12 34 56 01"
+}
\ No newline at end of file
diff --git a/tests/Models/bills/7.png b/tests/Models/bills/7.png
new file mode 100644
index 0000000..41ae689
Binary files /dev/null and b/tests/Models/bills/7.png differ
diff --git a/tests/Models/bills/8.json b/tests/Models/bills/8.json
new file mode 100644
index 0000000..98be9ba
--- /dev/null
+++ b/tests/Models/bills/8.json
@@ -0,0 +1,26 @@
+{
+ "invoice_number": "INV0041-1",
+ "grossSales": 56283100,
+ "netSales": 52601000,
+ "tax_amount": 3939800,
+ "tax_rate": 70000,
+ "bill_date": "2022-02-20",
+ "delivery_date": "",
+ "service_date": "",
+ "due_date": "2022-02-27",
+ "vat_id": "",
+ "tax_id": "",
+ "address": {
+ "name": "Company ABC",
+ "address": "Some Street 4",
+ "city": "12345 Rome",
+ "country": ""
+ },
+ "iban": "",
+ "elements": [],
+ "language": "en",
+ "currency": "USD",
+ "email": "",
+ "website": "",
+ "phone": ""
+}
\ No newline at end of file
diff --git a/tests/Models/bills/8.pdf b/tests/Models/bills/8.pdf
new file mode 100644
index 0000000..10a3a94
Binary files /dev/null and b/tests/Models/bills/8.pdf differ
diff --git a/tests/Models/bills/9.json b/tests/Models/bills/9.json
new file mode 100644
index 0000000..98be9ba
--- /dev/null
+++ b/tests/Models/bills/9.json
@@ -0,0 +1,26 @@
+{
+ "invoice_number": "INV0041-1",
+ "grossSales": 56283100,
+ "netSales": 52601000,
+ "tax_amount": 3939800,
+ "tax_rate": 70000,
+ "bill_date": "2022-02-20",
+ "delivery_date": "",
+ "service_date": "",
+ "due_date": "2022-02-27",
+ "vat_id": "",
+ "tax_id": "",
+ "address": {
+ "name": "Company ABC",
+ "address": "Some Street 4",
+ "city": "12345 Rome",
+ "country": ""
+ },
+ "iban": "",
+ "elements": [],
+ "language": "en",
+ "currency": "USD",
+ "email": "",
+ "website": "",
+ "phone": ""
+}
\ No newline at end of file
diff --git a/tests/Models/bills/9.pdf b/tests/Models/bills/9.pdf
new file mode 100644
index 0000000..99506f7
Binary files /dev/null and b/tests/Models/bills/9.pdf differ
| |