Merge branch 'develop'

This commit is contained in:
Dennis Eichhorn 2024-03-15 22:52:00 +00:00
commit 6cc41d1b2e
153 changed files with 9146 additions and 3805 deletions

View File

@ -1,35 +0,0 @@
---
name: Dev Bug Report
about: Create a report to help us improve
title: ''
labels: stat_backlog, type_bug
assignees: ''
---
# Bug Description
A clear and concise description of what the bug is.
# How to Reproduce
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
## Minimal Code Example
```
// your code ...
```
# Expected Behavior
A clear and concise description of what you expected to happen.
# Screenshots
If applicable, add screenshots to help explain your problem.
# Additional Information
Add any other context about the problem here.

View File

@ -1,18 +0,0 @@
---
name: Dev Feature Request
about: Suggest an idea for this project
title: ''
labels: stat_backlog, type_feature
assignees: ''
---
# What is the feature you request
* A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
* A clear and concise description of what you want to happen.
# Alternatives
A clear and concise description of any alternative solutions or features you've considered.
# Additional Information
Add any other context or screenshots about the feature request here.

View File

@ -1,40 +0,0 @@
---
name: User Bug Report
about: Create a report to help us improve
title: ''
labels: stat_backlog, type_bug
assignees: ''
---
# Bug Description
A clear and concise description of what the bug is.
# How to Reproduce
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
# Expected Behavior
A clear and concise description of what you expected to happen.
# Screenshots
If applicable, add screenshots to help explain your problem.
# System Information
- System: [e.g. PC or iPhone11, ...]
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- KarakaVersion [e.g. 22]
# Additional Information
Add any other context about the problem here.

View File

@ -1,21 +0,0 @@
---
name: User Feature Request
about: Suggest an idea for this project
title: ''
labels: stat_backlog, type_feature
assignees: ''
---
# What is the feature you request
* A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
* A clear and concise description of what you want to happen.
# Alternatives
A clear and concise description of any alternative solutions or features you've considered.
# Additional Information
Add any other context or screenshots about the feature request here.

View File

@ -1,9 +0,0 @@
[
{
"type": "setting",
"name": "1005100003",
"content": "[\"en\", \"de\"]",
"pattern": "",
"module": "Billing"
}
]

View File

@ -0,0 +1,26 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\Billing\Admin
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
use Modules\Billing\Controller\ApiController;
use Modules\Billing\Models\SettingsEnum;
return [
[
'type' => 'setting',
'name' => SettingsEnum::VALID_BILL_LANGUAGES,
'content' => '["en","de"]',
'pattern' => '',
'module' => ApiController::NAME,
],
];

View File

@ -38,6 +38,6 @@ class Admin
*/
public static function install(ApplicationAbstract $app, string $path) : void
{
\Modules\Admin\Admin\Installer::installExternal($app, ['path' => __DIR__ . '/Admin.install.json']);
\Modules\Admin\Admin\Installer::installExternal($app, ['path' => __DIR__ . '/Admin.install.php']);
}
}

View File

@ -36,14 +36,28 @@
},
{
"type": "type",
"name": "original",
"name": "internal",
"l11n": [
{
"title": "Original",
"title": "Internal",
"lang": "en"
},
{
"title": "Original",
"title": "Intern",
"lang": "de"
}
]
},
{
"type": "type",
"name": "external",
"l11n": [
{
"title": "External",
"lang": "en"
},
{
"title": "Extern",
"lang": "de"
}
]

View File

@ -54,11 +54,18 @@ class Media
],
[
'type' => 'setting',
'name' => SettingsEnum::ORIGINAL_MEDIA_TYPE,
'name' => SettingsEnum::INTERNAL_MEDIA_TYPE,
'content' => (string) $media['type'][1]['id'],
'pattern' => '\\d+',
'module' => 'Billing',
],
[
'type' => 'setting',
'name' => SettingsEnum::EXTERNAL_MEDIA_TYPE,
'content' => (string) $media['type'][2]['id'],
'pattern' => '\\d+',
'module' => 'Billing',
],
],
]
);

View File

@ -13,15 +13,17 @@
declare(strict_types=1);
use Modules\Billing\Models\NullBill;
use Modules\Media\Models\NullCollection;
use phpOMS\Localization\ISO3166NameEnum;
use phpOMS\Localization\ISO3166TwoEnum;
use phpOMS\Localization\Money;
use phpOMS\Stdlib\Base\FloatInt;
/** @var \phpOMS\Views\View $this */
/** @var \Modules\Media\Models\Collection $media */
$media = $this->getData('defaultTemplates');
require_once $media->findFile('.pdf.php')->getAbsolutePath();
/** @var \Modules\Media\Models\Collection $collection */
$collection = $this->data['defaultTemplates'] ?? new NullCollection();
require_once $collection->findFile('.pdf.php')->getAbsolutePath();
/** @var \Modules\Billing\Models\Bill $bill */
$bill = $this->data['bill'] ?? new NullBill();
@ -32,8 +34,8 @@ $pdf = new DefaultPdf();
$lang = include __DIR__ . '/lang.php';
$pdf->attributes['title_name'] = (string) ($this->data['bill_logo_name'] ?? 'Jingga');
$pdf->attributes['slogan'] = (string) ($this->data['bill_slogan'] ?? 'Business solutions made simple.');
$pdf->attributes['title_name'] = $this->data['bill_logo_name'] ?? 'Jingga';
$pdf->attributes['slogan'] = $this->data['bill_slogan'] ?? 'Business solutions made simple.';
$pdf->setHeaderData(
__DIR__ . '/logo.png', 15,
@ -47,22 +49,22 @@ $pdf->setSubject((string) ($this->data['bill_subtitle'] ?? ''));
$pdf->setKeywords(\implode(', ', (array) ($this->data['keywords'] ?? [])));
$pdf->language = $bill->language;
$pdf->attributes['legal_name'] = (string) ($this->data['legal_company_name'] ?? 'Jingga e. K.');
$pdf->attributes['address'] = (string) ($this->data['bill_company_address'] ?? 'Kirchstr. 33');
$pdf->attributes['city'] = (string) ($this->data['bill_company_city'] ?? '61191 Rosbach');
$pdf->attributes['legal_name'] = $this->data['legal_company_name'] ?? 'Jingga e. K.';
$pdf->attributes['address'] = $this->data['bill_company_address'] ?? 'Kirchstr. 33';
$pdf->attributes['city'] = $this->data['bill_company_city'] ?? '61191 Rosbach';
$pdf->attributes['ceo'] = (string) ($this->data['bill_company_ceo'] ?? 'Dennis Eichhorn');
$pdf->attributes['tax_office'] = (string) ($this->data['bill_company_tax_office'] ?? 'HRA 5058');
$pdf->attributes['tax_number'] = (string) ($this->data['bill_company_tax_id'] ?? 'DE362646968');
$pdf->attributes['terms'] = (string) ($this->data['bill_company_terms'] ?? 'https://jingga.app/terms');
$pdf->attributes['ceo'] = $this->data['bill_company_ceo'] ?? 'Dennis Eichhorn';
$pdf->attributes['tax_office'] = $this->data['bill_company_tax_office'] ?? 'HRA 5058';
$pdf->attributes['tax_number'] = $this->data['bill_company_tax_id'] ?? 'DE362646968';
$pdf->attributes['terms'] = $this->data['bill_company_terms'] ?? 'https://jingga.app/terms';
$pdf->attributes['bank_name'] = (string) ($this->data['bill_company_bank_name'] ?? 'Volksbank Mittelhessen');
$pdf->attributes['swift'] = (string) ($this->data['bill_company_swift'] ?? 'VBMHDE5F');
$pdf->attributes['bank_account'] = (string) ($this->data['bill_company_bank_account'] ?? 'DE62 5139 0000 0084 8044 10');
$pdf->attributes['bank_name'] = $this->data['bill_company_bank_name'] ?? 'Volksbank Mittelhessen';
$pdf->attributes['swift'] = $this->data['bill_company_swift'] ?? 'VBMHDE5F';
$pdf->attributes['bank_account'] = $this->data['bill_company_bank_account'] ?? 'DE62 5139 0000 0084 8044 10';
$pdf->attributes['website'] = (string) ($this->data['bill_company_website'] ?? 'www.jingga.app');
$pdf->attributes['email'] = (string) ($this->data['bill_company_email'] ?? 'info@jingga.app');
$pdf->attributes['phone'] = (string) ($this->data['bill_company_phone'] ?? '+49 152 04337728');
$pdf->attributes['website'] = $this->data['bill_company_website'] ?? 'www.jingga.app';
$pdf->attributes['email'] = $this->data['bill_company_email'] ?? 'info@jingga.app';
$pdf->attributes['phone'] = $this->data['bill_company_phone'] ?? '+49 152 04337728';
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
@ -73,17 +75,11 @@ $topPos = $pdf->getY();
// Set up default bill template
$billTypeName = \strtoupper($bill->type->getL11n());
// @todo: depending on amount of lines, there is a solution (html, or use backtracking of tcpdf)
// Address
$pdf->setY(50);
$pdf->setFont('helvetica', '', 10);
$countries = ISO3166NameEnum::getConstants();
$countryEnumName = ISO3166TwoEnum::getName($bill->billCountry);
$toCountry = \is_string($countryEnumName) && ($country = ISO3166NameEnum::getByName($countryEnumName)) !== null
? $country
: '';
$toCountry = ISO3166NameEnum::getBy2Code($bill->billCountry);
$addressString = \trim(
$bill->billTo . "\n"
@ -104,64 +100,58 @@ $pdf->Write(
);
$lineHeight = ($lineHeight - $pdf->getY()) / $addressLineCount;
$pageWidth = $pdf->getPageWidth();
$pageHeight = $pdf->getPageHeight();
// Bill head
$pdf->setFont('helvetica', 'B', 16);
$titleWidth = $pdf->getStringWidth($billTypeName, 'helvetica', 'B', 16);
$titleWidth = \is_array($titleWidth) ? \array_sum($titleWidth) : $titleWidth;
$pdf->setXY(
$rightPos = ($pdf->getPageWidth() - $titleWidth - \max(60 - $titleWidth, 0) - 15 - 2),
$rightPos = ($pageWidth - $titleWidth - \max(60 - $titleWidth, 0) - 15 - 2),
$topPos + 50 + $lineHeight * $addressLineCount - 38,
true
);
$pdf->setTextColor(255, 255, 255);
$pdf->setFillColor(255, 162, 7);
$pdf->Cell($pdf->getPageWidth() - $rightPos - 15, 0, $billTypeName, 0, 0, 'L', true);
$pdf->Cell($pageWidth - $rightPos - 15, 0, $billTypeName, 0, 0, 'L', true);
$pdf->setFont('helvetica', '', 10);
$pdf->setTextColor(255, 162, 7);
$pdf->setXY($rightPos, $tempY = $pdf->getY() + 10, true);
$pdf->MultiCell(
26, 30,
29, 30,
$lang[$pdf->language]['InvoiceNo'] . "\n"
. $lang[$pdf->language]['InvoiceDate'] . "\n"
. $lang[$pdf->language]['ServiceDate'] . "\n"
. $lang[$pdf->language]['CustomerNo'] . "\n"
. $lang[$pdf->language]['PO'] . "\n"
. $lang[$pdf->language]['REF'] . "\n"
. $lang[$pdf->language]['DueDate'],
0, 'L'
);
$pdf->setFont('helvetica', '', 10);
//$pdf->setFont('helvetica', '', 10);
$pdf->setTextColor(0, 0, 0);
$pdf->setXY($rightPos + 26 + 2, $tempY, true);
$pdf->setXY($rightPos + 29 + 2, $tempY, true);
$pdf->MultiCell(
25, 30,
$bill->number . "\n"
. ($bill->billDate?->format('Y-m-d') ?? '0') . "\n"
. ($bill->performanceDate?->format('Y-m-d') ?? '0') . "\n"
. $bill->accountNumber . "\n"
. '' . "\n" /* @todo: implement customer / supplier reference as string */
. $bill->external . "\n"
. ($bill->billDate?->format('Y-m-d') ?? '0'), /* Consider to add dueDate in addition */
0, 'L'
);
$pdf->Ln();
$pdf->setY($pdf->getY() - 30);
/*
$pdf->writeHTMLCell(
$pdf->getPageWidth() - 15 * 2, 0, null, null,
"<strong>Lorem ipsum dolor sit amet,</strong><br \><br \>Consectetur adipiscing elit. Vivamus ac massa sit amet eros posuere accumsan feugiat vel est. Maecenas ultricies enim eu eros rhoncus, volutpat cursus enim imperdiet. Aliquam et odio ipsum. Quisque dapibus scelerisque tempor. Phasellus purus lorem, venenatis eget pretium ac, convallis et ante. Aenean pulvinar justo consectetur mi tincidunt venenatis. Suspendisse ultricies enim id nulla facilisis lacinia. <br /><br />Nam congue nunc nunc, eu pellentesque eros aliquam ac. Nunc placerat elementum turpis, quis facilisis diam volutpat at. Suspendisse enim leo, convallis nec ornare eu, auctor nec purus. Nunc neque metus, feugiat quis justo nec, mollis dignissim risus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. In at ornare sem. Cras placerat, sapien sed ornare lacinia, mauris nulla volutpat nisl, eget dapibus nisl ipsum non est. Suspendisse ut nisl a ipsum rhoncus sodales.",
0, 0, false, true, 'J'
);
$pdf->Ln();
*/
$pdf->setY($pdf->getY() + 10);
$tempY = $pdf->getY();
$height = 0;
$pdf->setY($tempY - 20);
$header = [
$lang[$pdf->language]['Item'],
@ -170,11 +160,9 @@ $header = [
$lang[$pdf->language]['Total'],
];
$lines = $bill->getElements();
// Header
$headerCount = \count($header);
$w = [$pdf->getPageWidth() - 20 - 20 - 20 - 2 * 15, 20, 20, 20];
$w = [$pageWidth - 20 - 20 - 20 - 2 * 15, 20, 20, 20];
$pdf->setCellPadding(1);
@ -183,9 +171,9 @@ $first = true;
// Data
$fill = false;
foreach($lines as $line) {
// @todo: add support for empty lines (row = line)
if (/*$row === null || */$first || $pdf->getY() > $pdf->getPageHeight() - 40) {
foreach($bill->elements as $line) {
// @todo depending on amount of lines, there is a solution (html, or use backtracking of tcpdf)
if ($first || $pdf->getY() > $pageHeight - 40) {
$pdf->setFillColor(255, 162, 7);
$pdf->setTextColor(255);
$pdf->setDrawColor(255, 162, 7);
@ -209,110 +197,119 @@ foreach($lines as $line) {
$first = false;
}
// Discounts are shown below the original price -> additional line
// We don't want discount columns because that hints at customers they might be able to get discounts.
$lines = 1
+ ((int) ($line->discountQ->value > 0))
+ ((int) ($line->singleDiscountP->value > 0))
+ ((int) ($line->singleDiscountR->value > 0));
$tempY = $pdf->getY();
$pdf->writeHTMLCell($w[0], 10, null, null, $line->itemNumber . ' ' . $line->itemName, 0, 2, $fill);
//$pdf->writeHTMLCell($w[0], 10, null, null, $line->itemNumber . ' ' . $line->itemName, 0, 2, $fill);
$pdf->MultiCell($w[0], 10 * $lines, \trim($line->itemNumber . ' ' . $line->itemName), 0, 'L', $fill, 2, null, null, true, 0, true, true, 0, 'M', false);
$height = $pdf->getY() - $tempY;
$singleSalesPriceNet = Money::fromFloatInt($line->singleSalesPriceNet);
$totalSalesPriceNet = Money::fromFloatInt($line->totalSalesPriceNet);
$singleListPriceNet = Money::fromFloatInt($line->singleListPriceNet);
$totalSalesPriceNet = Money::fromFloatInt($line->totalSalesPriceNet);
$pdf->MultiCell($w[1], $height, (string) $line->getQuantity(), 0, 'L', $fill, 0, 15 + $w[0], $tempY, true, 0, false, true, 0, 'M', true);
$pdf->MultiCell($w[2], $height, $singleSalesPriceNet->getCurrency(2, symbol: ''), 0, 'L', $fill, 0, 15 + $w[0] + $w[1], $tempY, true, 0, false, true, 0, 'M', true);
$pdf->MultiCell($w[3], $height, $totalSalesPriceNet->getCurrency(2, symbol: ''), 0, 'L', $fill, 1, 15 + $w[0] + $w[1] + $w[2], $tempY, true, 0, false, true, 0, 'M', true);
if ($line->quantity->value === 0) {
$pdf->MultiCell($w[1] + $w[2] + $w[3], $height, '', 0, 'L', $fill, 0, 15 + $w[0], $tempY, true, 0, false, true, 0, 'M', true);
} else {
$pdf->MultiCell($w[1], $height, (string) $line->quantity->getAmount($line->container?->quantityDecimals ?? 0), 0, 'L', $fill, 0, 15 + $w[0], $tempY, true, 0, false, true, 0, 'M', true);
$pdf->MultiCell($w[2], $height, $singleListPriceNet->getCurrency(2, symbol: ''), 0, 'L', $fill, 0, 15 + $w[0] + $w[1], $tempY, true, 0, false, true, 0, 'M', true);
$pdf->MultiCell($w[3], $height, $totalSalesPriceNet->getCurrency(2, symbol: ''), 0, 'L', $fill, 1, 15 + $w[0] + $w[1] + $w[2], $tempY, true, 0, false, true, 0, 'M', true);
}
$fill = !$fill;
// get taxes
if (!isset($taxes[$line->taxR->getInt() / 100])) {
$taxes[$line->taxR->getInt() / 100] = $line->taxP;
if (!isset($taxes[$line->taxR->value / FloatInt::DIVISOR])) {
$taxes[$line->taxR->value / FloatInt::DIVISOR] = $line->taxP;
} else {
$taxes[$line->taxR->getInt() / 100]->add($line->taxP);
$taxes[$line->taxR->value / FloatInt::DIVISOR]->add($line->taxP);
}
}
$pdf->Cell(\array_sum($w), 0, '', 'T');
$pdf->Ln();
// We have to do the following because in some cases it doesn't set the Y position correctly after the table
// I assume it is related to if/else above. A html multicell might not correctly set the y position.
if (!empty($bill->elements)) {
$pdf->setY($tempY + $height);
if ($pdf->getY() > $pdf->getPageHeight() - 40) {
$pdf->AddPage();
}
$pdf->setFillColor(240, 240, 240);
$pdf->setTextColor(0);
$pdf->setDrawColor(240, 240, 240);
$pdf->setFont('helvetica', 'B', 10);
$tempY = $pdf->getY();
$netSales = Money::fromFloatInt($bill->netSales);
$pdf->setX($w[0] + $w[1] + 15);
$pdf->Cell($w[2], 7, $lang[$pdf->language]['Subtotal'], 0, 0, 'L', false);
$pdf->Cell($w[3], 7, $netSales->getCurrency(2, symbol: ''), 0, 0, 'L', false);
$pdf->Ln();
foreach ($taxes as $rate => $tax) {
$tax = Money::fromFloatInt($tax);
$pdf->setX($w[0] + $w[1] + 15);
$pdf->Cell($w[2], 7, $lang[$pdf->language]['Taxes'] . ' (' . $rate . '%)', 0, 0, 'L', false);
$pdf->Cell($w[3], 7, $tax->getCurrency(2, symbol: ''), 0, 0, 'L', false);
$pdf->Cell(\array_sum($w), 0, '', 'T');
$pdf->Ln();
if ($pdf->getY() > $pageHeight - 40) {
$pdf->AddPage();
}
$pdf->setFillColor(240, 240, 240);
$pdf->setTextColor(0);
$pdf->setDrawColor(240, 240, 240);
$pdf->setFont('helvetica', 'B', 10);
$tempY = $pdf->getY();
$netSales = Money::fromFloatInt($bill->netSales);
$pdf->setX($w[0] + $w[1] + 12);
$pdf->Cell($w[2], 7, $lang[$pdf->language]['Subtotal'], 0, 0, 'L', false);
$pdf->Cell($w[3], 7, $netSales->getCurrency(2, symbol: ''), 0, 0, 'L', false);
$pdf->Ln();
foreach ($taxes as $rate => $tax) {
$tax = Money::fromFloatInt($tax);
$pdf->setX($w[0] + $w[1] + 12);
$pdf->Cell($w[2], 7, $lang[$pdf->language]['Taxes'] . ' (' . $rate . '%)', 0, 0, 'L', false);
$pdf->Cell($w[3], 7, $tax->getCurrency(2, symbol: ''), 0, 0, 'L', false);
$pdf->Ln();
}
$pdf->setFillColor(255, 162, 7);
$pdf->setTextColor(255);
$pdf->setDrawColor(255, 162, 7);
//$pdf->setFont('helvetica', 'B', 10);
$grossSales = Money::fromFloatInt($bill->grossSales);
$pdf->setX($w[0] + $w[1] + 12);
$pdf->Cell($w[2], 7, \strtoupper($lang[$pdf->language]['Total']), 1, 0, 'L', true);
$pdf->Cell($w[3] + 3, 7, $grossSales->getCurrency(2, symbol: ''), 1, 0, 'L', true);
$pdf->Ln();
$tempY2 = $pdf->getY();
// @todo fix payment terms
$pdf->setTextColor(0);
$pdf->setFont('helvetica', 'B', 8);
$pdf->setY($tempY);
$pdf->Write(0, $lang[$pdf->language]['PaymentTerms'] . ': CreditCard', '', false, 'L', false, 0, false, false, 0);
$pdf->setFont('helvetica', '', 8);
$pdf->Write(0, $bill->paymentText, '', false, 'L', false, 0, false, false, 0);
$pdf->Ln();
// @todo fix terms
$pdf->setFont('helvetica', 'B', 8);
$pdf->Write(0, $lang[$pdf->language]['Terms'] . ': ' . $pdf->attributes['terms'], '', false, 'L', false, 0, false, false, 0);
$pdf->Ln();
//$pdf->setFont('helvetica', 'B', 8);
$pdf->Write(0, $lang[$pdf->language]['Currency'] . ': ' . $bill->currency, '', false, 'L', false, 0, false, false, 0);
$pdf->Ln();
//$pdf->setFont('helvetica', 'B', 8);
$pdf->Write(0, $lang[$pdf->language]['TaxRemark'], '', false, 'L', false, 0, false, false, 0);
$pdf->Ln();
$pdf->setFont('helvetica', '', 8);
$pdf->Write(0, $bill->termsText, '', false, 'L', false, 0, false, false, 0);
//$pdf->Ln();
//$pdf->setY($tempY2);
//$pdf->Ln();
}
$pdf->setFillColor(255, 162, 7);
$pdf->setTextColor(255);
$pdf->setDrawColor(255, 162, 7);
$pdf->setFont('helvetica', 'B', 10);
$grossSales = Money::fromFloatInt($bill->grossSales);
$pdf->setX($w[0] + $w[1] + 15);
$pdf->Cell($w[2], 7, \strtoupper($lang[$pdf->language]['Total']), 1, 0, 'L', true);
$pdf->Cell($w[3], 7, $grossSales->getCurrency(2, symbol: ''), 1, 0, 'L', true);
$pdf->Ln();
$tempY2 = $pdf->getY();
// @todo: fix payment terms
$pdf->setTextColor(0);
$pdf->setFont('helvetica', 'B', 8);
$pdf->setY($tempY);
$pdf->Write(0, $lang[$pdf->language]['PaymentTerms'] . ': CreditCard', '', false, 'L', false, 0, false, false, 0);
$pdf->setFont('helvetica', '', 8);
$pdf->Write(0, $bill->paymentText, '', false, 'L', false, 0, false, false, 0);
$pdf->Ln();
// @todo: fix terms
$pdf->setFont('helvetica', 'B', 8);
$pdf->Write(0, $lang[$pdf->language]['Terms'] . ': ' . $pdf->attributes['terms'], '', false, 'L', false, 0, false, false, 0);
$pdf->Ln();
$pdf->setFont('helvetica', 'B', 8);
$pdf->Write(0, $lang[$pdf->language]['Currency'] . ': ' . $bill->currency, '', false, 'L', false, 0, false, false, 0);
$pdf->Ln();
$pdf->setFont('helvetica', 'B', 8);
$pdf->Write(0, $lang[$pdf->language]['TaxRemark'], '', false, 'L', false, 0, false, false, 0);
$pdf->Ln();
$pdf->setFont('helvetica', '', 8);
$pdf->Write(0, $bill->termsText, '', false, 'L', false, 0, false, false, 0);
$pdf->Ln();
$pdf->setY($tempY2);
$pdf->Ln();
/*
$pdf->writeHTMLCell(
$pdf->getPageWidth() - 15 * 2, 0, null, null,
"Consectetur adipiscing elit. Vivamus ac massa sit amet eros posuere accumsan feugiat vel est. Maecenas ultricies enim eu eros rhoncus, volutpat cursus enim imperdiet. Aliquam et odio ipsum. Quisque dapibus scelerisque tempor. Phasellus purus lorem, venenatis eget pretium ac, convallis et ante. Aenean pulvinar justo consectetur mi tincidunt venenatis. Suspendisse ultricies enim id nulla facilisis lacinia. Nam congue nunc nunc, eu pellentesque eros aliquam ac.<br /><br />Nunc placerat elementum turpis, quis facilisis diam volutpat at. Suspendisse enim leo, convallis nec ornare eu, auctor nec purus. Nunc neque metus, feugiat quis justo nec, mollis dignissim risus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. In at ornare sem. Cras placerat, sapien sed ornare lacinia, mauris nulla volutpat nisl, eget dapibus nisl ipsum non est. Suspendisse ut nisl a ipsum rhoncus sodales.",
0, 0, false, true, 'J'
);
$pdf->Ln();
*/
//Close and output PDF document
$path = (string) ($this->data['path'] ?? (($bill->billDate?->format('Y-m-d') ?? '0') . '_' . $bill->number . '.pdf'));
$pdf->Output($path, 'I');

View File

@ -20,7 +20,7 @@ return [
'InvoiceDate' => 'Invoice Date',
'ServiceDate' => 'Service Date',
'CustomerNo' => 'Customer No.',
'PO' => 'PO',
'REF' => 'REF',
'DueDate' => 'Due Date',
'Item' => 'Item',
'Currency' => 'Currency',
@ -40,7 +40,7 @@ return [
'InvoiceDate' => 'Belegdatum',
'ServiceDate' => 'Leistungsdatum',
'CustomerNo' => 'Kundennummer',
'PO' => 'Kundenreferenz',
'REF' => 'REF',
'DueDate' => 'Fälligkeitsdatum',
'Item' => 'Artikel',
'Currency' => 'Währung',

View File

@ -9,13 +9,34 @@
"l11n": {
"en": {
"subject": "Billing",
"body": "<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Billing</title></head><body style=\"font-family: Arial, sans-serif; font-size: 16px; line-height: 1.5;\"><table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\"><tr><td><table align=\"center\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"600\" style=\"margin: 0 auto; background-color: #ffffff;\"><tr><td style=\"padding: 40px 0; text-align: center;\"><h1 style=\"margin-top: 0; color: #000000; font-size: 24px;\">Billing</h1><p style=\"margin-bottom: 20px;\">Dear {user_name},</p><p style=\"margin-bottom: 20px;\">Thank you for for doing business with us.</p><p style=\"margin-bottom: 20px;\">Attached kindly find your bill.</p><p style=\"margin-top: 40px;\">Jingga e.K. - www.jingga.app - CEO Dennis Eichhorn - Amtsgericht Friedberg HRA 5058</p></td></tr></table></td></tr></table></body></html>",
"body": "<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Billing</title></head><body style=\"font-family: Arial, sans-serif; font-size: 14px; line-height: 1.5;\"><table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\"><tr><td><table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"600\" style=\"margin: 0 auto; background-color: #ffffff;\"><tr><td style=\"padding: 40px 0;\"><h1 style=\"margin-top: 0; color: #000000; font-size: 24px; text-align: center;\">Billing</h1><p style=\"margin-bottom: 20px;\">Dear {user_name},</p><p style=\"margin-bottom: 20px;\">Thank you for for doing business with us.</p><p style=\"margin-bottom: 20px;\">Attached kindly find your bill.</p><p style=\"margin-top: 40px;\">Jingga e.K. - www.jingga.app - CEO Dennis Eichhorn - Amtsgericht Friedberg HRA 5058</p></td></tr></table></td></tr></table></body></html>",
"bodyalt": "Dear {user_name},\n\nThank you for doing business with us.\n\nAttached kindly find your bill.\n\n\nJingga e.K. - www.jingga.app - CEO Dennis Eichhorn - Amtsgericht Friedberg HRA 5058"
},
"de": {
"subject": "Rechnungsstellung",
"body": "<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Abrechnung</title></head><body style=\"font-family: Arial, sans-serif; font-size: 16px; line-height: 1.5;\"><table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\"><tr><td><table align=\"center\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"600\" style=\"margin: 0 auto; background-color: #ffffff;\"><tr><td style=\"padding: 40px 0; text-align: center;\"><h1 style=\"margin-top: 0; color: #000000; font-size: 24px;\">Abrechnung</h1><p style=\"margin-bottom: 20px;\">Sehr geehrte/r {user_name},</p><p style=\"margin-bottom: 20px;\">Vielen Dank für Ihre Geschäftsbeziehung mit uns.</p><p style=\"margin-bottom: 20px;\">Im Anhang finden Sie Ihre Rechnung.</p><p style=\"margin-top: 40px;\">Jingga e.K. - www.jingga.app - CEO Dennis Eichhorn - Amtsgericht Friedberg HRA 5058</p></td></tr></table></td></tr></table></body></html>",
"bodyalt": "Sehr geehrte/r {user_name},\n\nvielen Dank für Ihre Geschäftsbeziehung mit uns.\n\nIm Anhang finden Sie freundlicherweise Ihre Rechnung.\n\n\nJingga e.K. - www.jingga.app - CEO Dennis Eichhorn - Amtsgericht Friedberg HRA 5058"
"body": "<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Abrechnung</title></head><body style=\"font-family: Arial, sans-serif; font-size: 14px; line-height: 1.5;\"><table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\"><tr><td><table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"600\" style=\"margin: 0 auto; background-color: #ffffff;\"><tr><td style=\"padding: 40px 0;\"><h1 style=\"margin-top: 0; color: #000000; font-size: 24px; text-align: center;\">Abrechnung</h1><p style=\"margin-bottom: 20px;\">Sehr geehrte/r {user_name},</p><p style=\"margin-bottom: 20px;\">Vielen Dank für Ihre Geschäftsbeziehung mit uns.</p><p style=\"margin-bottom: 20px;\">Im Anhang finden Sie Ihre Rechnung.</p><p style=\"margin-top: 40px;\">Jingga e.K. - www.jingga.app - CEO Dennis Eichhorn - Amtsgericht Friedberg HRA 5058</p></td></tr></table></td></tr></table></body></html>",
"bodyalt": "Sehr geehrte/r {user_name},\n\nVielen Dank für Ihre Geschäftsbeziehung mit uns.\n\nIm Anhang finden Sie freundlicherweise Ihre Rechnung.\n\n\nJingga e.K. - www.jingga.app - CEO Dennis Eichhorn - Amtsgericht Friedberg HRA 5058"
}
},
"send": false
},
{
"type": "email_template",
"from": "",
"to": "",
"cc": "",
"bcc": "",
"ishtml": true,
"l11n": {
"en": {
"subject": "Order",
"body": "<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Order</title></head><body style=\"font-family: Arial, sans-serif; font-size: 14px; line-height: 1.5;\"><table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\"><tr><td><table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"600\" style=\"margin: 0 auto; background-color: #ffffff;\"><tr><td style=\"padding: 40px 0;\"><h1 style=\"margin-top: 0; color: #000000; font-size: 24px; text-align: center;\">Order</h1><p style=\"margin-bottom: 20px;\">Dear {user_name},</p><p style=\"margin-bottom: 20px;\">We are looking forward to doing business with you.</p><p style=\"margin-bottom: 20px;\">Attached kindly find our order.</p><p style=\"margin-top: 40px;\">Jingga e.K. - www.jingga.app - CEO Dennis Eichhorn - Amtsgericht Friedberg HRA 5058</p></td></tr></table></td></tr></table></body></html>",
"bodyalt": "Dear {user_name},\n\nWe are looking forward to doing business with you.\n\nAttached kindly find our order.\n\n\nJingga e.K. - www.jingga.app - CEO Dennis Eichhorn - Amtsgericht Friedberg HRA 5058"
},
"de": {
"subject": "Bestellung",
"body": "<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Bestellung</title></head><body style=\"font-family: Arial, sans-serif; font-size: 14px; line-height: 1.5;\"><table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\"><tr><td><table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"600\" style=\"margin: 0 auto; background-color: #ffffff;\"><tr><td style=\"padding: 40px 0;\"><h1 style=\"margin-top: 0; color: #000000; font-size: 24px; text-align: center;\">Bestellung</h1><p style=\"margin-bottom: 20px;\">Sehr geehrte/r {user_name},</p><p style=\"margin-bottom: 20px;\">Wir freuen uns eine Bestellung bei Ihnen aufgeben zu können.</p><p style=\"margin-bottom: 20px;\">Im Anhang finden Sie unsere Bestellung.</p><p style=\"margin-top: 40px;\">Jingga e.K. - www.jingga.app - CEO Dennis Eichhorn - Amtsgericht Friedberg HRA 5058</p></td></tr></table></td></tr></table></body></html>",
"bodyalt": "Sehr geehrte/r {user_name},\n\nWir freuen uns eine Bestellung bei Ihnen aufgeben zu können.\n\nIm Anhang finden Sie unsere Bestellung.\n\n\nJingga e.K. - www.jingga.app - CEO Dennis Eichhorn - Amtsgericht Friedberg HRA 5058"
}
},
"send": false

View File

@ -18,7 +18,6 @@ use Modules\Billing\Models\SettingsEnum;
use phpOMS\Application\ApplicationAbstract;
use phpOMS\Message\Http\HttpRequest;
use phpOMS\Message\Http\HttpResponse;
use phpOMS\Uri\HttpUri;
/**
* Media class.
@ -54,10 +53,16 @@ class Messages
'content' => (string) $messages['email_template'][0]['id'],
'module' => 'Billing',
],
[
'id' => null,
'name' => SettingsEnum::BILLING_SUPPLIER_EMAIL_TEMPLATE,
'content' => (string) $messages['email_template'][1]['id'],
'module' => 'Billing',
],
];
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('settings', \json_encode($settings));

View File

@ -5,7 +5,7 @@
"type": 2,
"subtype": 1,
"name": "Billing",
"uri": "{/base}/sales/bill/list",
"uri": "{/base}/sales/bill/list?{?}",
"target": "self",
"icon": null,
"order": 10,
@ -19,7 +19,7 @@
"type": 3,
"subtype": 1,
"name": "Open",
"uri": "{/base}/sales/bill/list",
"uri": "{/base}/sales/bill/list?{?}",
"target": "self",
"icon": null,
"order": 1,
@ -34,7 +34,7 @@
"type": 3,
"subtype": 1,
"name": "Archive",
"uri": "{/base}/sales/bill/archive",
"uri": "{/base}/sales/bill/archive?{?}",
"target": "self",
"icon": null,
"order": 5,
@ -57,6 +57,36 @@
"permission": { "permission": 4, "category": null, "element": null },
"parent": 1005104001,
"children": []
},
{
"id": 1005104401,
"pid": "/sales/bill",
"type": 3,
"subtype": 1,
"name": "PaymentTerms",
"uri": "{/base}/bill/payment/list?{?}",
"target": "self",
"icon": null,
"order": 15,
"from": "Billing",
"permission": { "permission": 4, "category": null, "element": null },
"parent": 1005104001,
"children": []
},
{
"id": 1005104501,
"pid": "/sales/bill",
"type": 3,
"subtype": 1,
"name": "ShippingTerms",
"uri": "{/base}/bill/shipping/list?{?}",
"target": "self",
"icon": null,
"order": 20,
"from": "Billing",
"permission": { "permission": 4, "category": null, "element": null },
"parent": 1005104001,
"children": []
}
]
},
@ -66,7 +96,7 @@
"type": 2,
"subtype": 1,
"name": "Billing",
"uri": "{/base}/purchase/bill/list",
"uri": "{/base}/purchase/bill/list?{?}",
"target": "self",
"icon": null,
"order": 10,
@ -80,7 +110,7 @@
"type": 3,
"subtype": 1,
"name": "Open",
"uri": "{/base}/purchase/bill/list",
"uri": "{/base}/purchase/bill/list?{?}",
"target": "self",
"icon": null,
"order": 1,
@ -95,7 +125,7 @@
"type": 3,
"subtype": 1,
"name": "Archive",
"uri": "{/base}/purchase/bill/archive",
"uri": "{/base}/purchase/bill/archive?{?}",
"target": "self",
"icon": null,
"order": 5,
@ -142,7 +172,7 @@
"type": 2,
"subtype": 1,
"name": "Billing",
"uri": "{/base}/warehouse/bill/list",
"uri": "{/base}/warehouse/bill/list?{?}",
"target": "self",
"icon": null,
"order": 5,
@ -156,7 +186,7 @@
"type": 3,
"subtype": 1,
"name": "List",
"uri": "{/base}/warehouse/bill/list",
"uri": "{/base}/warehouse/bill/list?{?}",
"target": "self",
"icon": null,
"order": 1,
@ -171,7 +201,7 @@
"type": 3,
"subtype": 1,
"name": "Archive",
"uri": "{/base}/warehouse/bill/archive",
"uri": "{/base}/warehouse/bill/archive?{?}",
"target": "self",
"icon": null,
"order": 1,
@ -203,7 +233,7 @@
"type": 3,
"subtype": 1,
"name": "Bill",
"uri": "{/base}/purchase/analysis/bill",
"uri": "{/base}/purchase/analysis/bill?{?}",
"target": "self",
"icon": null,
"order": 15,
@ -272,7 +302,7 @@
"order": 5,
"from": "Billing",
"permission": { "permission": 2, "category": null, "element": null },
"parent": 1003401001,
"parent": 1002101001,
"children": [
{
"id": 1005110101,

View File

@ -1,4 +1,184 @@
[
{
"type": 1,
"item_code": "GENERAL",
"account_code": "EU",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "AT",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "BE",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "BG",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "HR",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "CY",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "CZ",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "DK",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "EE",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "FI",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "FR",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "DE",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "GR",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "HU",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "IE",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "IT",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "LV",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "LT",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "LU",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "MT",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "NL",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "PL",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "PT",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "RO",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "SK",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "SI",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "ES",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "SE",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "GB",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "INT",
"tax_code": "SBIZ_0"
},
{
"type": 1,
"item_code": "SOFTWARE",

View File

@ -1,4 +1,207 @@
[
{
"type": 1,
"item_code": "GENERAL",
"account_code": "EU",
"tax_code": "EU_S0",
"account": "8400"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "AT",
"tax_code": "AT_S20"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "BE",
"tax_code": "BE_S21"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "BG",
"tax_code": "BG_S20"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "HR",
"tax_code": "HR_S25"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "CY",
"tax_code": "CY_S19"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "CZ",
"tax_code": "CZ_S21"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "DK",
"tax_code": "DK_S25"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "EE",
"tax_code": "EE_S20"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "FI",
"tax_code": "FI_S24"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "FR",
"tax_code": "FR_S20"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "DE",
"tax_code": "DE_M19",
"account": "8400"
},
{
"type": 2,
"item_code": "GENERAL",
"account_code": "DE",
"tax_code": "DE_V19",
"account": "3400"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "DE_0",
"tax_code": "SBIZ_0",
"account": "8195"
},
{
"type": 2,
"item_code": "GENERAL",
"account_code": "DE_0",
"tax_code": "SBIZ_0",
"account": "3349"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "GR",
"tax_code": "GR_S24"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "HU",
"tax_code": "HU_S27"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "IE",
"tax_code": "IE_S23"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "IT",
"tax_code": "IT_S22"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "LV",
"tax_code": "LV_S21"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "LT",
"tax_code": "LT_S21"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "LU",
"tax_code": "LU_S17"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "MT",
"tax_code": "MT_S18"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "NL",
"tax_code": "NL_S21"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "PL",
"tax_code": "PL_S23"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "PT",
"tax_code": "PT_S23"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "RO",
"tax_code": "RO_S19"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "SK",
"tax_code": "SK_S20"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "SI",
"tax_code": "SI_S22"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "ES",
"tax_code": "ES_S21"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "SE",
"tax_code": "SE_S25"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "GB",
"tax_code": "GB_S20"
},
{
"type": 1,
"item_code": "GENERAL",
"account_code": "INT",
"tax_code": "S0"
},
{
"type": 1,
"item_code": "SOFTWARE",
@ -69,7 +272,29 @@
"type": 1,
"item_code": "SOFTWARE",
"account_code": "DE",
"tax_code": "DE_S19"
"tax_code": "DE_M19",
"account": "8400"
},
{
"type": 2,
"item_code": "SOFTWARE",
"account_code": "DE",
"tax_code": "DE_V19",
"account": "3400"
},
{
"type": 1,
"item_code": "SOFTWARE",
"account_code": "DE_0",
"tax_code": "SBIZ_0",
"account": "8195"
},
{
"type": 2,
"item_code": "SOFTWARE",
"account_code": "DE_0",
"tax_code": "SBIZ_0",
"account": "3349"
},
{
"type": 1,
@ -249,7 +474,29 @@
"type": 1,
"item_code": "SERVICE",
"account_code": "DE",
"tax_code": "DE_S19"
"tax_code": "DE_M19",
"account": "8400"
},
{
"type": 2,
"item_code": "SERVICE",
"account_code": "DE",
"tax_code": "DE_V19",
"account": "3400"
},
{
"type": 1,
"item_code": "SERVICE",
"account_code": "DE_0",
"tax_code": "SBIZ_0",
"account": "8195"
},
{
"type": 2,
"item_code": "SERVICE",
"account_code": "DE_0",
"tax_code": "SBIZ_0",
"account": "3349"
},
{
"type": 1,

View File

@ -1,4 +1,112 @@
{
"billing_payment_term": {
"name": "billing_payment_term",
"fields": {
"billing_payment_term_id": {
"name": "billing_payment_term_id",
"type": "INT",
"null": false,
"primary": true,
"autoincrement": true
},
"billing_payment_term_code": {
"description": "In days",
"name": "billing_payment_term_code",
"type": "VARCHAR(100)",
"null": false,
"unique": true
},
"billing_payment_term_due": {
"description": "In days",
"name": "billing_payment_term_due",
"type": "INT",
"null": false
}
}
},
"billing_payment_term_l11n": {
"name": "billing_payment_term_l11n",
"fields": {
"billing_payment_term_l11n_id": {
"name": "billing_payment_term_l11n_id",
"type": "INT",
"null": false,
"primary": true,
"autoincrement": true
},
"billing_payment_term_l11n_name": {
"name": "billing_payment_term_l11n_name",
"type": "VARCHAR(255)",
"null": false
},
"billing_payment_term_l11n_term": {
"name": "billing_payment_term_l11n_term",
"type": "INT",
"null": false,
"foreignTable": "billing_payment_term",
"foreignKey": "billing_payment_term_id"
},
"billing_payment_term_l11n_language": {
"name": "billing_payment_term_l11n_language",
"type": "VARCHAR(2)",
"default": null,
"null": true,
"foreignTable": "language",
"foreignKey": "language_639_1"
}
}
},
"billing_shipping_term": {
"name": "billing_shipping_term",
"fields": {
"billing_shipping_term_id": {
"name": "billing_shipping_term_id",
"type": "INT",
"null": false,
"primary": true,
"autoincrement": true
},
"billing_shipping_term_code": {
"description": "In days",
"name": "billing_shipping_term_code",
"type": "VARCHAR(100)",
"null": false,
"unique": true
}
}
},
"billing_shipping_term_l11n": {
"name": "billing_shipping_term_l11n",
"fields": {
"billing_shipping_term_l11n_id": {
"name": "billing_shipping_term_l11n_id",
"type": "INT",
"null": false,
"primary": true,
"autoincrement": true
},
"billing_shipping_term_l11n_name": {
"name": "billing_shipping_term_l11n_name",
"type": "VARCHAR(255)",
"null": false
},
"billing_shipping_term_l11n_term": {
"name": "billing_shipping_term_l11n_term",
"type": "INT",
"null": false,
"foreignTable": "billing_shipping_term",
"foreignKey": "billing_shipping_term_id"
},
"billing_shipping_term_l11n_language": {
"name": "billing_shipping_term_l11n_language",
"type": "VARCHAR(2)",
"default": null,
"null": true,
"foreignTable": "language",
"foreignKey": "language_639_1"
}
}
},
"billing_price": {
"name": "billing_price",
"fields": {
@ -27,8 +135,16 @@
"foreignTable": "itemmgmt_item",
"foreignKey": "itemmgmt_item_id"
},
"billing_price_itemgroup": {
"name": "billing_price_itemgroup",
"billing_price_itemsalesgroup": {
"name": "billing_price_itemsalesgroup",
"type": "INT",
"null": true,
"default": null,
"foreignTable": "itemmgmt_attr_value",
"foreignKey": "itemmgmt_attr_value_id"
},
"billing_price_itemproductgroup": {
"name": "billing_price_itemproductgroup",
"type": "INT",
"null": true,
"default": null,
@ -126,6 +242,11 @@
"type": "TINYINT(1)",
"null": false
},
"billing_price_status": {
"name": "billing_price_status",
"type": "TINYINT(1)",
"null": false
},
"billing_price_quantity": {
"name": "billing_price_quantity",
"type": "BIGINT",
@ -234,6 +355,18 @@
"null": false,
"default": null
},
"billing_tax_tax1_account": {
"name": "billing_tax_tax1_account",
"type": "VARCHAR(10)",
"null": false,
"default": null
},
"billing_tax_tax2_account": {
"name": "billing_tax_tax2_account",
"type": "VARCHAR(10)",
"null": false,
"default": null
},
"billing_tax_refund_account": {
"name": "billing_tax_refund_account",
"type": "VARCHAR(10)",
@ -246,6 +379,24 @@
"null": false,
"default": null
},
"billing_tax_cashback_account": {
"name": "billing_tax_cashback_account",
"type": "VARCHAR(10)",
"null": false,
"default": null
},
"billing_tax_overpayment_account": {
"name": "billing_tax_overpayment_account",
"type": "VARCHAR(10)",
"null": false,
"default": null
},
"billing_tax_underpayment_account": {
"name": "billing_tax_underpayment_account",
"type": "VARCHAR(10)",
"null": false,
"default": null
},
"billing_tax_min_price": {
"name": "billing_tax_min_price",
"type": "BIGINT",
@ -312,12 +463,24 @@
"type": "TINYINT(1)",
"null": false
},
"billing_type_accounting": {
"description": "Is this bill relevant for accounting",
"name": "billing_type_accounting",
"type": "TINYINT(1)",
"null": false
},
"billing_type_transfer_sign": {
"description": "1 = from->to direction, -1 = to->from direction = credit note",
"name": "billing_type_transfer_sign",
"type": "TINYINT(1)",
"null": false
},
"billing_type_email": {
"description": "send email on archive",
"name": "billing_type_email",
"type": "TINYINT(1)",
"null": false
},
"billing_type_account_format": {
"name": "billing_type_account_format",
"type": "VARCHAR(255)",
@ -413,6 +576,11 @@
"type": "VARCHAR(255)",
"null": false
},
"billing_bill_external": {
"name": "billing_bill_external",
"type": "VARCHAR(255)",
"null": false
},
"billing_bill_info": {
"name": "billing_bill_info",
"type": "TEXT",
@ -437,17 +605,25 @@
},
"billing_bill_template": {
"name": "billing_bill_template",
"type": "INT",
"null": true,
"default": null,
"foreignTable": "media",
"foreignKey": "media_id"
"type": "TINYINT(1)",
"null": false
},
"billing_bill_archived": {
"name": "billing_bill_archived",
"type": "TINYINT(1)",
"null": false
},
"billing_bill_account_no": {
"name": "billing_bill_account_no",
"type": "VARCHAR(50)",
"null": false
},
"billing_bill_tax_type": {
"name": "billing_bill_tax_type",
"type": "INT",
"null": true,
"default": null
},
"billing_bill_supplier": {
"name": "billing_bill_supplier",
"type": "INT",
@ -585,21 +761,11 @@
"type": "BIGINT",
"null": false
},
"billing_bill_grossprofit": {
"name": "billing_bill_grossprofit",
"type": "BIGINT",
"null": false
},
"billing_bill_netcosts": {
"name": "billing_bill_netcosts",
"type": "BIGINT",
"null": false
},
"billing_bill_grosscosts": {
"name": "billing_bill_grosscosts",
"type": "BIGINT",
"null": false
},
"billing_bill_netsales": {
"name": "billing_bill_netsales",
"type": "BIGINT",
@ -615,8 +781,8 @@
"type": "BIGINT",
"null": false
},
"billing_bill_grossdiscount": {
"name": "billing_bill_grossdiscount",
"billing_bill_taxp": {
"name": "billing_bill_taxp",
"type": "BIGINT",
"null": false
},
@ -633,6 +799,11 @@
"foreignTable": "language",
"foreignKey": "language_639_1"
},
"billing_bill_fiaccount": {
"name": "billing_bill_fiaccount",
"type": "VARCHAR(10)",
"null": false
},
"billing_bill_referral": {
"name": "billing_bill_referral",
"type": "INT",
@ -641,18 +812,41 @@
"foreignTable": "account",
"foreignKey": "account_id"
},
"billing_bill_referral_name": {
"name": "billing_bill_referral_name",
"type": "VARCHAR(255)",
"default": null,
"null": true
},
"billing_bill_reference": {
"name": "billing_bill_reference",
"type": "INT",
"null": false
},
"billing_bill_accsegment": {
"description": "attribute values",
"name": "billing_bill_accsegment",
"type": "INT",
"null": true,
"default": null
},
"billing_bill_accsection": {
"description": "attribute values",
"name": "billing_bill_accsection",
"type": "INT",
"null": true,
"default": null
},
"billing_bill_accgroup": {
"description": "attribute values",
"name": "billing_bill_accgroup",
"type": "INT",
"null": true,
"default": null
},
"billing_bill_acctype": {
"description": "attribute values",
"name": "billing_bill_acctype",
"type": "INT",
"null": true,
"default": null
},
"billing_bill_payment": {
"description": "should this handle the dues?",
"name": "billing_bill_payment",
"type": "INT",
"null": false
@ -666,7 +860,10 @@
"billing_bill_paymentterms": {
"name": "billing_bill_paymentterms",
"type": "INT",
"null": false
"null": true,
"default": null,
"foreignTable": "billing_payment_term",
"foreignKey": "billing_payment_term_id"
},
"billing_bill_paymentterms_text": {
"name": "billing_bill_paymentterms_text",
@ -677,7 +874,10 @@
"billing_bill_ship_type": {
"name": "billing_bill_ship_type",
"type": "INT",
"null": false
"null": true,
"default": null,
"foreignTable": "billing_shipping_term",
"foreignKey": "billing_shipping_term_id"
},
"billing_bill_ship_text": {
"name": "billing_bill_ship_text",
@ -784,6 +984,14 @@
"foreignTable": "itemmgmt_item",
"foreignKey": "itemmgmt_item_id"
},
"billing_bill_element_container": {
"name": "billing_bill_element_container",
"type": "INT",
"null": false,
"default": null,
"foreignTable": "itemmgmt_item_container",
"foreignKey": "itemmgmt_item_container_id"
},
"billing_bill_element_subscription": {
"name": "billing_bill_element_subscription",
"type": "INT",
@ -815,7 +1023,7 @@
},
"billing_bill_element_quantity": {
"name": "billing_bill_element_quantity",
"type": "INT",
"type": "BIGINT",
"null": false
},
"billing_bill_element_single_netlistprice": {
@ -848,6 +1056,12 @@
"null": true,
"default": null
},
"billing_bill_element_single_effectivenetsalesprice": {
"name": "billing_bill_element_single_effectivenetsalesprice",
"type": "BIGINT",
"null": true,
"default": null
},
"billing_bill_element_single_grosssalesprice": {
"name": "billing_bill_element_single_grosssalesprice",
"type": "BIGINT",
@ -872,48 +1086,24 @@
"null": true,
"default": null
},
"billing_bill_element_single_grosspurchaseprice": {
"name": "billing_bill_element_single_grosspurchaseprice",
"type": "BIGINT",
"null": true,
"default": null
},
"billing_bill_element_total_netpurchaseprice": {
"name": "billing_bill_element_total_netpurchaseprice",
"type": "BIGINT",
"null": true,
"default": null
},
"billing_bill_element_total_grosspurchaseprice": {
"name": "billing_bill_element_total_grosspurchaseprice",
"type": "BIGINT",
"null": true,
"default": null
},
"billing_bill_element_single_netprofit": {
"name": "billing_bill_element_single_netprofit",
"type": "BIGINT",
"null": true,
"default": null
},
"billing_bill_element_single_grossprofit": {
"name": "billing_bill_element_single_grossprofit",
"type": "BIGINT",
"null": true,
"default": null
},
"billing_bill_element_total_netprofit": {
"name": "billing_bill_element_total_netprofit",
"type": "BIGINT",
"null": true,
"default": null
},
"billing_bill_element_total_grossprofit": {
"name": "billing_bill_element_total_grossprofit",
"type": "BIGINT",
"null": true,
"default": null
},
"billing_bill_element_price_discount_single": {
"name": "billing_bill_element_price_discount_single",
"type": "BIGINT",
@ -962,6 +1152,14 @@
"null": true,
"default": null
},
"billing_bill_element_tax_combination": {
"name": "billing_bill_element_tax_combination",
"type": "INT",
"null": true,
"default": null,
"foreignTable": "billing_tax",
"foreignKey": "billing_tax_id"
},
"billing_bill_element_tax_type": {
"name": "billing_bill_element_tax_type",
"type": "VARCHAR(10)",
@ -986,6 +1184,51 @@
"null": true,
"default": null
},
"billing_bill_element_segment": {
"description": "attribute values",
"name": "billing_bill_element_segment",
"type": "INT",
"null": true,
"default": null,
"foreignTable": "itemmgmt_attr_value",
"foreignKey": "itemmgmt_attr_value_id"
},
"billing_bill_element_section": {
"description": "attribute values",
"name": "billing_bill_element_section",
"type": "INT",
"null": true,
"default": null,
"foreignTable": "itemmgmt_attr_value",
"foreignKey": "itemmgmt_attr_value_id"
},
"billing_bill_element_salesgroup": {
"description": "attribute values",
"name": "billing_bill_element_salesgroup",
"type": "INT",
"null": true,
"default": null,
"foreignTable": "itemmgmt_attr_value",
"foreignKey": "itemmgmt_attr_value_id"
},
"billing_bill_element_productgroup": {
"description": "attribute values",
"name": "billing_bill_element_productgroup",
"type": "INT",
"null": true,
"default": null,
"foreignTable": "itemmgmt_attr_value",
"foreignKey": "itemmgmt_attr_value_id"
},
"billing_bill_element_itemtype": {
"description": "attribute values",
"name": "billing_bill_element_itemtype",
"type": "INT",
"null": true,
"default": null,
"foreignTable": "itemmgmt_attr_value",
"foreignKey": "itemmgmt_attr_value_id"
},
"billing_bill_element_bill": {
"name": "billing_bill_element_bill",
"type": "INT",
@ -993,9 +1236,24 @@
"foreignTable": "billing_bill",
"foreignKey": "billing_bill_id"
},
"billing_bill_element_fiaccount": {
"name": "billing_bill_element_fiaccount",
"type": "VARCHAR(10)",
"null": false
},
"billing_bill_element_costcenter": {
"name": "billing_bill_element_costcenter",
"type": "VARCHAR(10)",
"null": false
},
"billing_bill_element_costobject": {
"name": "billing_bill_element_costobject",
"type": "VARCHAR(10)",
"null": false
},
"billing_bill_element_promotion": {
"name": "billing_bill_element_promotion",
"type": "INT",
"type": "VARCHAR(10)",
"default": null,
"null": true
},
@ -1038,6 +1296,16 @@
"type": "TINYINT(1)",
"null": false
},
"billing_attr_type_repeatable": {
"name": "billing_attr_type_repeatable",
"type": "TINYINT(1)",
"null": false
},
"billing_attr_type_internal": {
"name": "billing_attr_type_internal",
"type": "TINYINT(1)",
"null": false
},
"billing_attr_type_required": {
"description": "Every item must have this attribute type if set to true.",
"name": "billing_attr_type_required",

View File

@ -0,0 +1,149 @@
[
{
"name": "PORI",
"l11n": {
"en" : "Payment on receipt of invoice",
"de" : "Zahlung fällig sofort nach Rechnungserhalt"
}
},
{
"name": "Net 10",
"l11n": {
"en" : "Payment is due 10 days after the invoice date",
"de" : "Zahlung fällig 10 Tage nach Rechnungsdatum"
}
},
{
"name": "Net 15",
"l11n": {
"en" : "Payment is due 15 days after the invoice date",
"de" : "Zahlung fällig 15 Tage nach Rechnungsdatum"
}
},
{
"name": "Net 30",
"l11n": {
"en" : "Payment is due 30 days after the invoice date",
"de" : "Zahlung fällig 30 Tage nach Rechnungsdatum"
}
},
{
"name": "Net 60",
"l11n": {
"en" : "Payment is due 60 days after the invoice date",
"de" : "Zahlung fällig 60 Tage nach Rechnungsdatum"
}
},
{
"name": "Net 90",
"l11n": {
"en" : "Payment is due 90 days after the invoice date",
"de" : "Zahlung fällig 90 Tage nach Rechnungsdatum"
}
},
{
"name": "COD",
"l11n": {
"en" : "Payment is made at the time of delivery",
"de" : "Zahlung fällig bei Lieferung"
}
},
{
"name": "CWO",
"l11n": {
"en" : "Cash with order",
"de" : "Zahlung fällig bei Bestellung"
}
},
{
"name": "CBS",
"l11n": {
"en" : "Cash before shipment",
"de" : "Zahlung fällig vor Lieferung"
}
},
{
"name": "Monthly",
"l11n": {
"en" : "Due at the end of the month",
"de" : "Zahlung fällig zum Monatsende des Rechnungsdatums"
}
},
{
"name": "PIA",
"l11n": {
"en" : "Payment in advance (pay-as-you-use)",
"de" : "Vorauszahlung (Pay-as-you-use)"
}
},
{
"name": "2/10 Net 30",
"l11n": {
"en" : "2% discount for payment within 10 days after invoice date; otherwise, the full amount is due in 30 days after invoice date",
"de" : "2% Skonto innerhalb von 10 Tagen nach Rechnungsdatum, andernfalls fällig zum vollen Betrag nach 30 Tagen nach Rechnungsdatum"
}
},
{
"name": "3/10 Net 30",
"l11n": {
"en" : "3% discount for payment within 10 days after invoice date; otherwise, the full amount is due in 30 days after invoice date",
"de" : "3% Skonto innerhalb von 10 Tagen nach Rechnungsdatum, andernfalls fällig zum vollen Betrag nach 30 Tagen nach Rechnungsdatum"
}
},
{
"name": "2/15 Net 30",
"l11n": {
"en" : "2% discount for payment within 15 days after invoice date; otherwise, the full amount is due in 30 days after invoice date",
"de" : "2% Skonto innerhalb von 15 Tagen nach Rechnungsdatum, andernfalls fällig zum vollen Betrag nach 30 Tagen nach Rechnungsdatum"
}
},
{
"name": "3/15 Net 30",
"l11n": {
"en" : "3% discount for payment within 15 days after invoice date; otherwise, the full amount is due in 30 days after invoice date",
"de" : "3% Skonto innerhalb von 15 Tagen nach Rechnungsdatum, andernfalls fällig zum vollen Betrag nach 30 Tagen nach Rechnungsdatum"
}
},
{
"name": "Escrow",
"l11n": {
"en" : "Payment is held by a third party until certain conditions are met (Escrow)",
"de" : "Die Zahlung wird von einer dritten Partei zurückgehalten, bis bestimmte Bedingungen erfüllt sind (Escrow)"
}
},
{
"name": "Open account",
"l11n": {
"en" : "There is a credit agreement and payment is expected within the agreed period",
"de" : "Es besteht eine Kreditvereinbarung, und die Zahlung wird innerhalb der vereinbarten Frist erwartet"
}
},
{
"name": "Installment payments",
"l11n": {
"en" : "Payments are divided into installments over a defined period",
"de" : "Die Zahlungen werden in Raten über einen bestimmten Zeitraum verteilt"
}
},
{
"name": "LC",
"l11n": {
"en" : "Payment is guaranteed by a bank upon presentation of specified documents",
"de" : "Die Zahlung wird von einer Bank gegen Vorlage bestimmter Dokumente garantiert"
}
},
{
"name": "Consignment",
"l11n": {
"en" : "Payment is made only after the goods are sold by the buyer",
"de" : "Die Zahlung erfolgt erst nach dem Verkauf der Ware durch den Käufer"
}
},
{
"name": "Retainer",
"l11n": {
"en" : "A partial upfront payment to secure services",
"de" : "Eine teilweise Vorauszahlung zur Sicherung der Dienstleistungen"
}
}
]

View File

@ -0,0 +1,79 @@
[
{
"name": "EXW",
"l11n": {
"en": "Incoterms 2020 Ex Works",
"de": "Incotemrs 2020 Ex Works"
}
},
{
"name": "FCA",
"l11n": {
"en": "Incoterms 2020 Free Carrier",
"de": "Incotemrs 2020 Free Carrier"
}
},
{
"name": "CPT",
"l11n": {
"en": "Incoterms 2020 Carriage Paid to",
"de": "Incotemrs 2020 Carriage Paid to"
}
},
{
"name": "CIP",
"l11n": {
"en": "Incoterms 2020 Carriage and Insurance Paid To",
"de": "Incotemrs 2020 Carriage and Insurance Paid To"
}
},
{
"name": "DAP",
"l11n": {
"en": "Incoterms 2020 Delivered at Place",
"de": "Incotemrs 2020 Delivered at Place"
}
},
{
"name": "DPU",
"l11n": {
"en": "Incoterms 2020 Delivered at Place Unloaded",
"de": "Incotemrs 2020 Delivered at Place Unloaded"
}
},
{
"name": "DDP",
"l11n": {
"en": "Incoterms 2020 Delivered Duty Paid",
"de": "Incotemrs 2020 Delivered Duty Paid"
}
},
{
"name": "FAS",
"l11n": {
"en": "Incoterms 2020 Free Alongside Ship",
"de": "Incotemrs 2020 Free Alongside Ship"
}
},
{
"name": "FOB",
"l11n": {
"en": "Incoterms 2020 Free on Board",
"de": "Incotemrs 2020 Free on Board"
}
},
{
"name": "CFR",
"l11n": {
"en": "Incoterms 2020 Cost and Freight",
"de": "Incotemrs 2020 Cost and Freight"
}
},
{
"name": "CIF",
"l11n": {
"en": "Incoterms 2020 Cost Insurance and Freight",
"de": "Incotemrs 2020 Cost Insurance and Freight"
}
}
]

View File

@ -1,8 +1,11 @@
[
{
"name": "sales_offer",
"numberFormat": "{y}-{sequence}",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 1,
"sign": 1,
"email": true,
"isAccounting": false,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -12,8 +15,11 @@
},
{
"name": "sales_order_confirmation",
"numberFormat": "{y}-{sequence}",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 1,
"sign": 1,
"email": true,
"isAccounting": false,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -23,8 +29,11 @@
},
{
"name": "sales_delivery_note",
"numberFormat": "{y}-{sequence}",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 1,
"sign": 1,
"email": false,
"isAccounting": false,
"transferStock": true,
"isTemplate": false,
"l11n": {
@ -34,8 +43,11 @@
},
{
"name": "sales_invoice",
"numberFormat": "{y}-{sequence}",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 1,
"sign": 1,
"email": true,
"isAccounting": true,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -45,8 +57,11 @@
},
{
"name": "sales_proforma_invoice",
"numberFormat": "{y}-{sequence}",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 1,
"sign": 1,
"email": true,
"isAccounting": false,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -56,8 +71,11 @@
},
{
"name": "sales_credit_note",
"numberFormat": "{y}-{sequence}",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 1,
"sign": -1,
"email": true,
"isAccounting": true,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -67,8 +85,11 @@
},
{
"name": "sales_reverse_invoice",
"numberFormat": "{y}-{sequence}",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 1,
"sign": -1,
"email": true,
"isAccounting": true,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -78,8 +99,11 @@
},
{
"name": "purchase_offer",
"numberFormat": "{y}-{sequence}",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 2,
"sign": -1,
"email": false,
"isAccounting": false,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -88,9 +112,26 @@
}
},
{
"name": "purchase_order_confirmation",
"numberFormat": "{y}-{sequence}",
"name": "purchase_order",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 2,
"sign": -1,
"email": true,
"isAccounting": false,
"transferStock": false,
"isTemplate": false,
"l11n": {
"en": "Order",
"de": "Bestellung"
}
},
{
"name": "purchase_order_confirmation",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 2,
"sign": -1,
"email": false,
"isAccounting": false,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -100,8 +141,11 @@
},
{
"name": "purchase_delivery_note",
"numberFormat": "{y}-{sequence}",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 2,
"sign": -1,
"email": false,
"isAccounting": false,
"transferStock": true,
"isTemplate": false,
"l11n": {
@ -111,8 +155,11 @@
},
{
"name": "purchase_invoice",
"numberFormat": "{y}-{sequence}",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 2,
"sign": -1,
"email": false,
"isAccounting": true,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -122,8 +169,11 @@
},
{
"name": "purchase_proforma_invoice",
"numberFormat": "{y}-{sequence}",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 2,
"sign": -1,
"email": false,
"isAccounting": false,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -133,8 +183,11 @@
},
{
"name": "purchase_credit_note",
"numberFormat": "{y}-{sequence}",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 2,
"sign": 1,
"email": false,
"isAccounting": true,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -144,8 +197,11 @@
},
{
"name": "purchase_reverse_invoice",
"numberFormat": "{y}-{sequence}",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 2,
"sign": 1,
"email": false,
"isAccounting": true,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -155,8 +211,10 @@
},
{
"name": "stock_movement",
"numberFormat": "{y}-{sequence}",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 4,
"sign": 1,
"isAccounting": false,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -165,20 +223,37 @@
}
},
{
"name": "stock_scrapping",
"numberFormat": "{y}-{sequence}",
"name": "stock_decrease",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 4,
"transferStock": false,
"sign": -1,
"isAccounting": false,
"transferStock": true,
"isTemplate": false,
"l11n": {
"en": "Scrapping",
"de": "Verschrottung"
"en": "Stock Decrease",
"de": "Lagerausbuchung"
}
},
{
"name": "sales_subscritpion",
"numberFormat": "{y}-{sequence}",
"name": "stock_increase",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 4,
"sign": 1,
"isAccounting": false,
"transferStock": true,
"isTemplate": false,
"l11n": {
"en": "Stock Increase",
"de": "Lagereinbuchung"
}
},
{
"name": "sales_subscription",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 1,
"sign": 1,
"isAccounting": true,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -187,36 +262,16 @@
}
},
{
"name": "sales_template",
"numberFormat": "{y}-{sequence}",
"transferType": 1,
"transferStock": false,
"isTemplate": true,
"l11n": {
"en": "Template",
"de": "Vorlage"
}
},
{
"name": "purchase_subscritpion",
"numberFormat": "{y}-{sequence}",
"name": "purchase_subscription",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 2,
"sign": -1,
"isAccounting": true,
"transferStock": false,
"isTemplate": false,
"l11n": {
"en": "Subscription",
"de": "Abonnement"
}
},
{
"name": "purchase_template",
"numberFormat": "{y}-{sequence}",
"transferType": 2,
"transferStock": false,
"isTemplate": true,
"l11n": {
"en": "Template",
"de": "Vorlage"
}
}
]

View File

@ -17,14 +17,13 @@ namespace Modules\Billing\Admin;
use Modules\Billing\Models\BillTransferType;
use Modules\ClientManagement\Models\Attribute\ClientAttributeTypeMapper;
use Modules\ItemManagement\Models\Attribute\ItemAttributeTypeMapper;
use Modules\SupplierManagement\Models\SupplierAttributeTypeMapper;
use Modules\SupplierManagement\Models\Attribute\SupplierAttributeTypeMapper;
use phpOMS\Application\ApplicationAbstract;
use phpOMS\Config\SettingsInterface;
use phpOMS\Message\Http\HttpRequest;
use phpOMS\Message\Http\HttpResponse;
use phpOMS\Module\InstallerAbstract;
use phpOMS\Module\ModuleInfo;
use phpOMS\Uri\HttpUri;
/**
* Installer class.
@ -99,6 +98,26 @@ final class Installer extends InstallerAbstract
$attrTypes = self::createBillAttributeTypes($app, $attributes);
$attrValues = self::createBillAttributeValues($app, $attrTypes, $attributes);
/* Payment terms */
$fileContent = \file_get_contents(__DIR__ . '/Install/paymentterms.json');
if ($fileContent === false) {
return;
}
/** @var array $terms */
$terms = \json_decode($fileContent, true);
$paymentTypeArray = self::createPaymentTerms($app, $terms);
/* Shipping terms */
$fileContent = \file_get_contents(__DIR__ . '/Install/shippingterms.json');
if ($fileContent === false) {
return;
}
/** @var array $terms */
$terms = \json_decode($fileContent, true);
$shippingTypeArray = self::createShippingTerms($app, $terms);
}
/**
@ -116,19 +135,21 @@ final class Installer extends InstallerAbstract
/** @var array $billAttrType */
$billAttrType = [];
/** @var \Modules\Billing\Controller\ApiController $module */
$module = $app->moduleManager->getModuleInstance('Billing');
/** @var \Modules\Billing\Controller\ApiAttributeController $module */
$module = $app->moduleManager->get('Billing', 'ApiAttribute');
/** @var array $attribute */
foreach ($attributes as $attribute) {
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('name', $attribute['name'] ?? '');
$request->setData('title', \reset($attribute['l11n']));
$request->setData('language', \array_keys($attribute['l11n'])[0] ?? 'en');
$request->setData('is_required', $attribute['is_required'] ?? false);
$request->setData('repeatable', $attribute['repeatable'] ?? false);
$request->setData('internal', $attribute['internal'] ?? false);
$request->setData('custom', $attribute['is_custom_allowed'] ?? false);
$request->setData('validation_pattern', $attribute['validation_pattern'] ?? '');
$request->setData('datatype', (int) $attribute['value_type']);
@ -153,7 +174,7 @@ final class Installer extends InstallerAbstract
}
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('title', $l11n);
@ -183,8 +204,8 @@ final class Installer extends InstallerAbstract
/** @var array<string, array> $billAttrValue */
$billAttrValue = [];
/** @var \Modules\Billing\Controller\ApiController $module */
$module = $app->moduleManager->getModuleInstance('Billing');
/** @var \Modules\Billing\Controller\ApiAttributeController $module */
$module = $app->moduleManager->get('Billing', 'ApiAttribute');
foreach ($attributes as $attribute) {
$billAttrValue[$attribute['name']] = [];
@ -192,7 +213,7 @@ final class Installer extends InstallerAbstract
/** @var array $value */
foreach ($attribute['values'] as $value) {
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('value', $value['value'] ?? '');
@ -226,7 +247,7 @@ final class Installer extends InstallerAbstract
}
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('title', $l11n);
@ -255,8 +276,8 @@ final class Installer extends InstallerAbstract
{
$result = [];
/** @var \Modules\Billing\Controller\ApiController $module */
$module = $app->moduleManager->getModuleInstance('Billing');
/** @var \Modules\Billing\Controller\ApiTaxController $module */
$module = $app->moduleManager->get('Billing', 'ApiTax');
/** @var \Modules\Attribute\Models\AttributeType $itemAttributeSales */
$itemAttributeSales = ItemAttributeTypeMapper::get()
@ -283,13 +304,14 @@ final class Installer extends InstallerAbstract
: $supplierAttributeSales->getDefaultByValue($tax['account_code']);
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('tax_type', $tax['type']);
$request->setData('tax_code', $tax['tax_code']);
$request->setData('item_code', $itemValue->id);
$request->setData('account_code', $accountValue->id);
$request->setData('account', $tax['account'] ?? null);
$module->apiTaxCombinationCreate($request, $response);
@ -323,23 +345,23 @@ final class Installer extends InstallerAbstract
{
$billTypes = [];
/** @var \Modules\Billing\Controller\ApiController $module */
$module = $app->moduleManager->getModuleInstance('Billing');
// @todo: allow multiple alternative bill templates
// @todo: implement ordering of templates
/** @var \Modules\Billing\Controller\ApiBillTypeController $module */
$module = $app->moduleManager->get('Billing', 'ApiBillType');
foreach ($types as $type) {
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('name', $type['name'] ?? '');
$request->setData('title', \reset($type['l11n']));
$request->setData('language', \array_keys($type['l11n'])[0] ?? 'en');
$request->setData('number_format', $type['numberFormat'] ?? '{id}');
$request->setData('sign', $type['sign'] ?? 1);
$request->setData('email', $type['email'] ?? false);
$request->setData('transfer_stock', $type['transferStock'] ?? false);
$request->setData('is_template', $type['isTemplate'] ?? false);
$request->setData('is_accounting', $type['isAccounting'] ?? false);
$request->setData('transfer_type', $type['transferType'] ?? BillTransferType::SALES);
$request->setData('template', $template);
@ -364,7 +386,7 @@ final class Installer extends InstallerAbstract
}
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('title', $l11n);
@ -377,4 +399,124 @@ final class Installer extends InstallerAbstract
return $billTypes;
}
/**
* Install default payment terms
*
* @param ApplicationAbstract $app Application
* @param array $types Payment term definitions
*
* @return array
*
* @since 1.0.0
*/
private static function createPaymentTerms(ApplicationAbstract $app, array $types) : array
{
/** @var array<string, array> $paymentTerms */
$paymentTerms = [];
/** @var \Modules\Billing\Controller\ApiController $module */
$module = $app->moduleManager->get('Billing', 'Api');
/** @var array $type */
foreach ($types as $type) {
$response = new HttpResponse();
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('name', $type['name'] ?? '');
$request->setData('title', \reset($type['l11n']));
$module->apiPaymentTermCreate($request, $response);
$responseData = $response->getData('');
if (!\is_array($responseData)) {
continue;
}
$paymentTerms[$type['name']] = \is_array($responseData['response'])
? $responseData['response']
: $responseData['response']->toArray();
$isFirst = true;
foreach ($type['l11n'] as $language => $l11n) {
if ($isFirst) {
$isFirst = false;
continue;
}
$response = new HttpResponse();
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('title', $l11n);
$request->setData('language', $language);
$request->setData('type', $paymentTerms[$type['name']]['id']);
$module->apiPaymentTermL11nCreate($request, $response);
}
}
return $paymentTerms;
}
/**
* Install default shipping terms
*
* @param ApplicationAbstract $app Application
* @param array $types Shipping term definitions
*
* @return array
*
* @since 1.0.0
*/
private static function createShippingTerms(ApplicationAbstract $app, array $types) : array
{
/** @var array<string, array> $shippingTerms */
$shippingTerms = [];
/** @var \Modules\Billing\Controller\ApiController $module */
$module = $app->moduleManager->get('Billing', 'Api');
/** @var array $type */
foreach ($types as $type) {
$response = new HttpResponse();
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('name', $type['name'] ?? '');
$request->setData('title', \reset($type['l11n']));
$module->apiShippingTermCreate($request, $response);
$responseData = $response->getData('');
if (!\is_array($responseData)) {
continue;
}
$shippingTerms[$type['name']] = \is_array($responseData['response'])
? $responseData['response']
: $responseData['response']->toArray();
$isFirst = true;
foreach ($type['l11n'] as $language => $l11n) {
if ($isFirst) {
$isFirst = false;
continue;
}
$response = new HttpResponse();
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('title', $l11n);
$request->setData('language', $language);
$request->setData('type', $shippingTerms[$type['name']]['id']);
$module->apiShippingTermL11nCreate($request, $response);
}
}
return $shippingTerms;
}
}

View File

@ -4,7 +4,7 @@ declare(strict_types=1);
use phpOMS\Router\RouteVerb;
return [
'^/billing/bill/purchase/parse.*$' => [
'^/billing/bill/purchase/parse( .*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\CliController:cliParseSupplierBill',
'verb' => RouteVerb::ANY,

View File

@ -18,7 +18,7 @@ use phpOMS\Account\PermissionType;
use phpOMS\Router\RouteVerb;
return [
'^.*/bill/render.*$' => [
'^.*/bill/render(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\ApiBillController:apiMediaRender',
'verb' => RouteVerb::GET,
@ -29,4 +29,37 @@ return [
],
],
],
'^.*/bill/render/preview(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\ApiBillController:apiPreviewRender',
'verb' => RouteVerb::GET,
'permission' => [
'module' => BackendController::NAME,
'type' => PermissionType::CREATE,
'state' => PermissionCategory::SALES_INVOICE,
],
],
],
'^.*/bill/price(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\ApiPriceController:apiPriceCreate',
'verb' => RouteVerb::GET,
'permission' => [
'module' => BackendController::NAME,
'type' => PermissionType::CREATE,
'state' => PermissionCategory::PRICE,
],
],
],
'^.*/bill/parse(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\ApiPurchaseController:apiInvoiceParse',
'verb' => RouteVerb::SET,
'permission' => [
'module' => BackendController::NAME,
'type' => PermissionType::MODIFY,
'state' => PermissionCategory::PURCHASE_INVOICE,
],
],
],
];

View File

@ -18,7 +18,7 @@ use phpOMS\Account\PermissionType;
use phpOMS\Router\RouteVerb;
return [
'^.*/sales/bill/create.*$' => [
'^.*/sales/bill/create(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingSalesInvoiceCreate',
'verb' => RouteVerb::GET,
@ -29,7 +29,7 @@ return [
],
],
],
'^.*/sales/bill/list.*$' => [
'^.*/sales/bill/list(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingSalesList',
'verb' => RouteVerb::GET,
@ -40,7 +40,18 @@ return [
],
],
],
'^.*/sales/bill\?.*$' => [
'^.*/sales/bill/archive(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingSalesArchive',
'verb' => RouteVerb::GET,
'permission' => [
'module' => BackendController::NAME,
'type' => PermissionType::READ,
'state' => PermissionCategory::SALES_INVOICE,
],
],
],
'^.*/sales/bill(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingSalesInvoice',
'verb' => RouteVerb::GET,
@ -52,7 +63,7 @@ return [
],
],
'^.*/purchase/bill/create.*$' => [
'^.*/purchase/bill/create(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingPurchaseInvoiceCreate',
'verb' => RouteVerb::GET,
@ -63,7 +74,7 @@ return [
],
],
],
'^.*/purchase/bill/list.*$' => [
'^.*/purchase/bill/list(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingPurchaseList',
'verb' => RouteVerb::GET,
@ -74,7 +85,18 @@ return [
],
],
],
'^.*/purchase/bill\?.*$' => [
'^.*/purchase/bill/archive(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingPurchaseArchive',
'verb' => RouteVerb::GET,
'permission' => [
'module' => BackendController::NAME,
'type' => PermissionType::READ,
'state' => PermissionCategory::PURCHASE_INVOICE,
],
],
],
'^.*/purchase/bill(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingPurchaseInvoice',
'verb' => RouteVerb::GET,
@ -85,7 +107,7 @@ return [
],
],
],
'^.*/purchase/bill/upload\?.*$' => [
'^.*/purchase/bill/upload(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingPurchaseInvoiceUpload',
'verb' => RouteVerb::GET,
@ -97,7 +119,7 @@ return [
],
],
'^.*/warehouse/bill/create.*$' => [
'^.*/warehouse/bill/create(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingStockInvoiceCreate',
'verb' => RouteVerb::GET,
@ -108,7 +130,7 @@ return [
],
],
],
'^.*/warehouse/bill/list.*$' => [
'^.*/warehouse/bill/list(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingStockList',
'verb' => RouteVerb::GET,
@ -119,7 +141,18 @@ return [
],
],
],
'^.*/warehouse/bill\?.*$' => [
'^.*/warehouse/bill/archive(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingStockArchive',
'verb' => RouteVerb::GET,
'permission' => [
'module' => BackendController::NAME,
'type' => PermissionType::READ,
'state' => PermissionCategory::PURCHASE_INVOICE,
],
],
],
'^.*/warehouse/bill(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingStockInvoice',
'verb' => RouteVerb::GET,
@ -131,7 +164,7 @@ return [
],
],
'^.*/private/purchase/recognition/dashboard.*$' => [
'^.*/private/purchase/recognition/dashboard(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewPrivatePurchaseBillDashboard',
'verb' => RouteVerb::GET,
@ -142,7 +175,7 @@ return [
],
],
],
'^.*/private/purchase/recognition/upload.*$' => [
'^.*/private/purchase/recognition/upload(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewPrivatePurchaseBillUpload',
'verb' => RouteVerb::GET,
@ -153,7 +186,7 @@ return [
],
],
],
'^.*/private/purchase/recognition/bill.*$' => [
'^.*/private/purchase/recognition/bill(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewPrivateBillingPurchaseInvoice',
'verb' => RouteVerb::GET,
@ -164,7 +197,7 @@ return [
],
],
],
'^.*/purchase/recognition/dashboard.*$' => [
'^.*/purchase/recognition/dashboard(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewPrivatePurchaseBillDashboard',
'verb' => RouteVerb::GET,
@ -175,7 +208,7 @@ return [
],
],
],
'^.*/purchase/recognition/upload.*$' => [
'^.*/purchase/recognition/upload(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewPrivatePurchaseBillUpload',
'verb' => RouteVerb::GET,
@ -186,7 +219,7 @@ return [
],
],
],
'^.*/purchase/recognition/bill.*$' => [
'^.*/purchase/recognition/bill(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewPrivateBillingPurchaseInvoice',
'verb' => RouteVerb::GET,
@ -197,4 +230,49 @@ return [
],
],
],
'^.*/bill/payment/list(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewPaymentList',
'verb' => RouteVerb::GET,
'permission' => [
'module' => BackendController::NAME,
'type' => PermissionType::READ,
'state' => PermissionCategory::PAYMENT_TERM,
],
],
],
'^.*/bill/payment/view(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewPaymentView',
'verb' => RouteVerb::GET,
'permission' => [
'module' => BackendController::NAME,
'type' => PermissionType::READ,
'state' => PermissionCategory::PAYMENT_TERM,
],
],
],
'^.*/bill/shipping/list(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewShippingList',
'verb' => RouteVerb::GET,
'permission' => [
'module' => BackendController::NAME,
'type' => PermissionType::READ,
'state' => PermissionCategory::SHIPPING_TERM,
],
],
],
'^.*/bill/shipping/view(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewShippingView',
'verb' => RouteVerb::GET,
'permission' => [
'module' => BackendController::NAME,
'type' => PermissionType::READ,
'state' => PermissionCategory::SHIPPING_TERM,
],
],
],
];

View File

@ -61,7 +61,26 @@ final class ApiAttributeController extends Controller
return;
}
$type = BillAttributeTypeMapper::get()->with('defaults')->where('id', (int) $request->getData('type'))->execute();
$type = BillAttributeTypeMapper::get()
->with('defaults')
->where('id', (int) $request->getData('type'))
->execute();
if (!$type->repeatable) {
$attr = BillAttributeMapper::count()
->with('type')
->where('type/id', $type->id)
->where('ref', (int) $request->getData('ref'))
->executeCount();
if ($attr > 0) {
$response->header->status = RequestStatusCode::R_409;
$this->createInvalidCreateResponse($request, $response, $val);
return;
}
}
$attribute = $this->createAttributeFromRequest($request, $type);
$this->createModel($request->header->account, $attribute, BillAttributeMapper::class, 'attribute', $request->getOrigin());
$this->createStandardCreateResponse($request, $response, $attribute);
@ -148,13 +167,20 @@ final class ApiAttributeController extends Controller
->where('id', $request->getDataInt('type') ?? 0)
->execute();
if ($type->isInternal) {
$response->header->status = RequestStatusCode::R_403;
$this->createInvalidCreateResponse($request, $response, $val);
return;
}
$attrValue = $this->createAttributeValueFromRequest($request, $type);
$this->createModel($request->header->account, $attrValue, BillAttributeValueMapper::class, 'attr_value', $request->getOrigin());
if ($attrValue->isDefault) {
$this->createModelRelation(
$request->header->account,
(int) $request->getData('type'),
$type->id,
$attrValue->id,
BillAttributeTypeMapper::class, 'defaults', '', $request->getOrigin()
);
@ -377,7 +403,7 @@ final class ApiAttributeController extends Controller
*
* @api
*
* @todo: implement
* @todo Implement API function
*
* @since 1.0.0
*/
@ -448,7 +474,7 @@ final class ApiAttributeController extends Controller
*/
public function apiBillAttributeValueDelete(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
// @todo: I don't think values can be deleted? Only Attributes
// @todo I don't think values can be deleted? Only Attributes
// However, It should be possible to remove UNUSED default values
// either here or other function?
// if (!empty($val = $this->validateAttributeValueDelete($request))) {

File diff suppressed because it is too large Load Diff

View File

@ -75,11 +75,17 @@ final class ApiBillTypeController extends Controller
private function createBillTypeFromRequest(RequestAbstract $request) : BillType
{
$billType = new BillType($request->getDataString('name') ?? '');
$billType->setL11n($request->getDataString('title') ?? '', $request->getDataString('language') ?? ISO639x1Enum::_EN);
$billType->setL11n(
$request->getDataString('title') ?? '',
ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? ISO639x1Enum::_EN
);
$billType->numberFormat = $request->getDataString('number_format') ?? '{id}';
$billType->sign = $request->getDataInt('sign') ?? 1;
$billType->email = $request->getDataBool('email') ?? false;
$billType->transferStock = $request->getDataBool('transfer_stock') ?? false;
$billType->isTemplate = $request->getDataBool('is_template') ?? false;
$billType->transferType = $request->getDataInt('transfer_type') ?? BillTransferType::SALES;
$billType->isAccounting = $request->getDataBool('is_accounting') ?? false;
$billType->transferType = BillTransferType::tryFromValue($request->getDataInt('transfer_type')) ?? BillTransferType::SALES;
$billType->defaultTemplate = $request->hasData('template')
? new NullCollection((int) $request->getData('template'))
: null;
@ -150,12 +156,10 @@ final class ApiBillTypeController extends Controller
*/
private function createBillTypeL11nFromRequest(RequestAbstract $request) : BaseStringL11n
{
$billTypeL11n = new BaseStringL11n();
$billTypeL11n->ref = $request->getDataInt('type') ?? 0;
$billTypeL11n->setLanguage(
$request->getDataString('language') ?? $request->header->l11n->language
);
$billTypeL11n->content = $request->getDataString('title') ?? '';
$billTypeL11n = new BaseStringL11n();
$billTypeL11n->ref = $request->getDataInt('type') ?? 0;
$billTypeL11n->language = ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? $request->header->l11n->language;
$billTypeL11n->content = $request->getDataString('title') ?? '';
return $billTypeL11n;
}
@ -219,7 +223,7 @@ final class ApiBillTypeController extends Controller
*
* @return BillType
*
* @todo: implement
* @todo Implement API update function
*
* @since 1.0.0
*/
@ -228,7 +232,8 @@ final class ApiBillTypeController extends Controller
$new->numberFormat = $request->getDataString('number_format') ?? $new->numberFormat;
$new->transferStock = $request->getDataBool('transfer_stock') ?? $new->transferStock;
$new->isTemplate = $request->getDataBool('is_template') ?? $new->isTemplate;
$new->transferType = $request->getDataInt('transfer_type') ?? $new->transferType;
$new->isAccounting = $request->getDataBool('is_accounting') ?? $new->isAccounting;
$new->transferType = BillTransferType::tryFromValue($request->getDataInt('transfer_type')) ?? $new->transferType;
$new->defaultTemplate = $request->hasData('template')
? new NullCollection((int) $request->getData('template'))
: $new->defaultTemplate;
@ -243,7 +248,7 @@ final class ApiBillTypeController extends Controller
*
* @return array<string, bool>
*
* @todo: implement
* @todo Implement API validation function
*
* @since 1.0.0
*/
@ -346,11 +351,9 @@ final class ApiBillTypeController extends Controller
*/
public function updateBillTypeL11nFromRequest(RequestAbstract $request, BaseStringL11n $new) : BaseStringL11n
{
$new->ref = $request->getDataInt('type') ?? $new->ref;
$new->setLanguage(
$request->getDataString('language') ?? $new->language
);
$new->content = $request->getDataString('title') ?? $new->content;
$new->ref = $request->getDataInt('type') ?? $new->ref;
$new->language = ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? $new->language;
$new->content = $request->getDataString('title') ?? $new->content;
return $new;
}

View File

@ -15,6 +15,14 @@ declare(strict_types=1);
namespace Modules\Billing\Controller;
use Modules\Billing\Models\PaymentTermL11nMapper;
use Modules\Billing\Models\PaymentTermMapper;
use Modules\Billing\Models\ShippingTermL11nMapper;
use Modules\Billing\Models\ShippingTermMapper;
use phpOMS\Localization\BaseStringL11n;
use phpOMS\Localization\BaseStringL11nType;
use phpOMS\Localization\ISO639x1Enum;
use phpOMS\Message\Http\RequestStatusCode;
use phpOMS\Message\RequestAbstract;
use phpOMS\Message\ResponseAbstract;
@ -29,7 +37,7 @@ use phpOMS\Message\ResponseAbstract;
final class ApiController extends Controller
{
/**
* Api method to update a bill
* Api method to create item payment type
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
@ -41,49 +49,63 @@ final class ApiController extends Controller
*
* @since 1.0.0
*/
public function apiBillUpdate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
public function apiPaymentTermCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiBill')->apiBillUpdate($request, $response, $data);
if (!empty($val = $this->validatePaymentTermCreate($request))) {
$response->header->status = RequestStatusCode::R_400;
$this->createInvalidCreateResponse($request, $response, $val);
return;
}
$paymentTerm = $this->createPaymentTermFromRequest($request);
$this->createModel($request->header->account, $paymentTerm, PaymentTermMapper::class, 'payment_term', $request->getOrigin());
$this->createStandardCreateResponse($request, $response, $paymentTerm);
}
/**
* Api method to create a bill
* Validate payment create request
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
* @param RequestAbstract $request Request
*
* @return void
*
* @api
* @return array<string, bool>
*
* @since 1.0.0
*/
public function apiBillCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
private function validatePaymentTermCreate(RequestAbstract $request) : array
{
$this->app->moduleManager->get('Billing', 'ApiBill')->apiBillCreate($request, $response, $data);
$val = [];
if (($val['title'] = !$request->hasData('title'))
|| ($val['name'] = !$request->hasData('name'))
) {
return $val;
}
return [];
}
/**
* Api method to create a bill
* Method to create payment from request.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
* @param RequestAbstract $request Request
*
* @return void
*
* @api
* @return BaseStringL11nType
*
* @since 1.0.0
*/
public function apiMediaAddToBill(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
private function createPaymentTermFromRequest(RequestAbstract $request) : BaseStringL11nType
{
$this->app->moduleManager->get('Billing', 'ApiBill')->apiMediaAddToBill($request, $response, $data);
$paymentTerm = new BaseStringL11nType($request->getDataString('name') ?? '');
$paymentTerm->setL11n(
$request->getDataString('title') ?? '',
ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? ISO639x1Enum::_EN
);
return $paymentTerm;
}
/**
* Api method to create a bill element
* Api method to create item payment l11n
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
@ -95,49 +117,62 @@ final class ApiController extends Controller
*
* @since 1.0.0
*/
public function apiBillElementCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
public function apiPaymentTermL11nCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiBill')->apiBillElementCreate($request, $response, $data);
if (!empty($val = $this->validatePaymentTermL11nCreate($request))) {
$response->header->status = RequestStatusCode::R_400;
$this->createInvalidCreateResponse($request, $response, $val);
return;
}
$paymentL11n = $this->createPaymentTermL11nFromRequest($request);
$this->createModel($request->header->account, $paymentL11n, PaymentTermL11nMapper::class, 'payment_term_l11n', $request->getOrigin());
$this->createStandardCreateResponse($request, $response, $paymentL11n);
}
/**
* Api method to create a bill preview
* Validate payment l11n create request
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
* @param RequestAbstract $request Request
*
* @return void
*
* @api
* @return array<string, bool>
*
* @since 1.0.0
*/
public function apiPreviewRender(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
private function validatePaymentTermL11nCreate(RequestAbstract $request) : array
{
$this->app->moduleManager->get('Billing', 'ApiBill')->apiPreviewRender($request, $response, $data);
$val = [];
if (($val['title'] = !$request->hasData('title'))
|| ($val['type'] = !$request->hasData('type'))
) {
return $val;
}
return [];
}
/**
* Api method to create and archive a bill
* Method to create payment l11n from request.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
* @param RequestAbstract $request Request
*
* @return void
*
* @api
* @return BaseStringL11n
*
* @since 1.0.0
*/
public function apiBillPdfArchiveCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
private function createPaymentTermL11nFromRequest(RequestAbstract $request) : BaseStringL11n
{
$this->app->moduleManager->get('Billing', 'ApiBill')->apiBillPdfArchiveCreate($request, $response, $data);
$paymentL11n = new BaseStringL11n();
$paymentL11n->ref = $request->getDataInt('type') ?? 0;
$paymentL11n->language = ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? $request->header->l11n->language;
$paymentL11n->content = $request->getDataString('title') ?? '';
return $paymentL11n;
}
/**
* Api method to create a bill
* Api method to create shipping term type
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
@ -149,49 +184,63 @@ final class ApiController extends Controller
*
* @since 1.0.0
*/
public function apiBillPdfCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
public function apiShippingTermCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiBill')->apiBillPdfCreate($request, $response, $data);
if (!empty($val = $this->validateShippingTermCreate($request))) {
$response->header->status = RequestStatusCode::R_400;
$this->createInvalidCreateResponse($request, $response, $val);
return;
}
$shippingTerm = $this->createShippingTermFromRequest($request);
$this->createModel($request->header->account, $shippingTerm, ShippingTermMapper::class, 'shipping_term', $request->getOrigin());
$this->createStandardCreateResponse($request, $response, $shippingTerm);
}
/**
* Api method to create bill files
* Validate shipping create request
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
* @param RequestAbstract $request Request
*
* @return void
*
* @api
* @return array<string, bool>
*
* @since 1.0.0
*/
public function apiNoteCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
private function validateShippingTermCreate(RequestAbstract $request) : array
{
$this->app->moduleManager->get('Billing', 'ApiBill')->apiNoteCreate($request, $response, $data);
$val = [];
if (($val['title'] = !$request->hasData('title'))
|| ($val['name'] = !$request->hasData('name'))
) {
return $val;
}
return [];
}
/**
* Api method to create bill files
* Method to create shipping from request.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
* @param RequestAbstract $request Request
*
* @return void
*
* @api
* @return BaseStringL11nType
*
* @since 1.0.0
*/
public function apiSupplierBillUpload(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
private function createShippingTermFromRequest(RequestAbstract $request) : BaseStringL11nType
{
$this->app->moduleManager->get('Billing', 'ApiPurchase')->apiSupplierBillUpload($request, $response, $data);
$shippingTerm = new BaseStringL11nType($request->getDataString('name') ?? '');
$shippingTerm->setL11n(
$request->getDataString('title') ?? '',
ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? ISO639x1Enum::_EN
);
return $shippingTerm;
}
/**
* Api method to create item bill type
* Api method to create shipping term l11n
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
@ -203,169 +252,57 @@ final class ApiController extends Controller
*
* @since 1.0.0
*/
public function apiBillTypeCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
public function apiShippingTermL11nCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiBillType')->apiBillTypeCreate($request, $response, $data);
if (!empty($val = $this->validateShippingTermL11nCreate($request))) {
$response->header->status = RequestStatusCode::R_400;
$this->createInvalidCreateResponse($request, $response, $val);
return;
}
$shippingL11n = $this->createShippingTermL11nFromRequest($request);
$this->createModel($request->header->account, $shippingL11n, ShippingTermL11nMapper::class, 'shipping_term_l11n', $request->getOrigin());
$this->createStandardCreateResponse($request, $response, $shippingL11n);
}
/**
* Api method to create item attribute l11n
* Validate shipping l11n create request
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
* @param RequestAbstract $request Request
*
* @return void
*
* @api
* @return array<string, bool>
*
* @since 1.0.0
*/
public function apiBillTypeL11nCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
private function validateShippingTermL11nCreate(RequestAbstract $request) : array
{
$this->app->moduleManager->get('Billing', 'ApiBillType')->apiBillTypeL11nCreate($request, $response, $data);
$val = [];
if (($val['title'] = !$request->hasData('title'))
|| ($val['type'] = !$request->hasData('type'))
) {
return $val;
}
return [];
}
/**
* Api method to create item bill type
* Method to create shipping l11n from request.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
* @param RequestAbstract $request Request
*
* @return void
*
* @api
* @return BaseStringL11n
*
* @since 1.0.0
*/
public function apiTaxCombinationCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
private function createShippingTermL11nFromRequest(RequestAbstract $request) : BaseStringL11n
{
$this->app->moduleManager->get('Billing', 'ApiTax')->apiTaxCombinationCreate($request, $response, $data);
}
$shippingL11n = new BaseStringL11n();
$shippingL11n->ref = $request->getDataInt('type') ?? 0;
$shippingL11n->language = ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? $request->header->l11n->language;
$shippingL11n->content = $request->getDataString('title') ?? '';
/**
* Api method to create item bill type
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiPriceCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiPrice')->apiPriceCreate($request, $response, $data);
}
/**
* Api method to create item attribute
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiBillAttributeCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiAttribute')->apiBillAttributeCreate($request, $response, $data);
}
/**
* Api method to create bill attribute l11n
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiBillAttributeTypeL11nCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiAttribute')->apiBillAttributeTypeL11nCreate($request, $response, $data);
}
/**
* Api method to create bill attribute type
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiBillAttributeTypeCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiAttribute')->apiBillAttributeTypeCreate($request, $response, $data);
}
/**
* Api method to create bill attribute value
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiBillAttributeValueCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiAttribute')->apiBillAttributeValueCreate($request, $response, $data);
}
/**
* Api method to create bill attribute l11n
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiBillAttributeValueL11nCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiAttribute')->apiBillAttributeValueL11nCreate($request, $response, $data);
}
/**
* Api method to find subscriptions
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiSubscriptionFind(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
return $shippingL11n;
}
}

View File

@ -16,22 +16,25 @@ declare(strict_types=1);
namespace Modules\Billing\Controller;
use Modules\Attribute\Models\NullAttributeValue;
use Modules\Billing\Models\Price\NullPrice;
use Modules\Billing\Models\Price\Price;
use Modules\Billing\Models\Price\PriceMapper;
use Modules\Billing\Models\Price\PriceStatus;
use Modules\Billing\Models\Price\PriceType;
use Modules\Billing\Models\Tax\TaxCombinationMapper;
use Modules\ClientManagement\Models\Client;
use Modules\ClientManagement\Models\ClientMapper;
use Modules\ClientManagement\Models\NullClient;
use Modules\ItemManagement\Models\Item;
use Modules\ItemManagement\Models\ItemMapper;
use Modules\ItemManagement\Models\NullItem;
use Modules\SupplierManagement\Models\NullSupplier;
use Modules\SupplierManagement\Models\Supplier;
use Modules\SupplierManagement\Models\SupplierMapper;
use phpOMS\Localization\ISO4217CharEnum;
use phpOMS\Message\Http\RequestStatusCode;
use phpOMS\Message\RequestAbstract;
use phpOMS\Message\ResponseAbstract;
use phpOMS\Stdlib\Base\FloatInt;
use phpOMS\System\MimeType;
/**
* Billing class.
@ -44,98 +47,177 @@ use phpOMS\System\MimeType;
final class ApiPriceController extends Controller
{
/**
* Api method to find items
* Find the best price for a client/supplier and an item
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
* @param RequestAbstract $request Request
* @param null|Item $item Item to find the price for (alternatively, price_item in request)
* @param null|Client $client Client to find the price for (alternatively, client in request)
* @param null|Supplier $supplier Supplier to find the price for (alternatively, supplier in request)
*
* @return void
*
* @api
* @return array
*
* @since 1.0.0
*/
public function apiPricingFind(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
public function findBestPrice(
RequestAbstract $request,
?Item $item = null,
?Client $client = null, ?Supplier $supplier = null
) : array
{
$item ??= new NullItem();
$client ??= new NullClient();
$supplier ??= new NullSupplier();
// Get item
/** @var null|\Modules\ItemManagement\Models\Item $item */
$item = null;
if ($request->hasData('price_item')) {
/** @var null|\Modules\ItemManagement\Models\Item $item */
if ($item->id === 0 && $request->hasData('price_item')) {
/** @var \Modules\ItemManagement\Models\Item $item */
$item = ItemMapper::get()
->with('attributes')
->with('attributes/type')
->with('attributes/value')
->where('id', (int) $request->getData('price_item'))
->where('attributes/type/name', ['segment', 'section', 'sales_group', 'product_group', 'product_type'], 'IN')
->execute();
}
// Get account
/** @var null|\Modules\ClientManagement\Models\Client|\Modules\SupplierManagement\Models\Supplier $account */
$account = null;
/** @var null|\Modules\ClientManagement\Models\Client $client */
$client = null;
/** @var null|\Modules\SupplierManagement\Models\Supplier $supplier */
$supplier = null;
if ($request->hasData('price_client')) {
// Get client
if ($client->id === 0 && $request->hasData('client')) {
/** @var \Modules\ClientManagement\Models\Client $client */
$client = ClientMapper::get()
->with('mainAddress')
->with('attributes')
->with('attributes/type')
->with('attributes/value')
->where('id', (int) $request->getData('price_client'))
->where('id', (int) $request->getData('client'))
->where('attributes/type/name', ['segment', 'section', 'client_group', 'client_type'], 'IN')
->execute();
/** @var \Modules\ClientManagement\Models\Client */
$account = $client;
} else {
/** @var \Modules\SupplierManagement\Models\Supplier $supplier */
$supplier = SupplierMapper::get()
->with('attributes')
->with('attributes/type')
->with('attributes/value')
->where('id', (int) $request->getData('price_supplier'))
->execute();
/** @var \Modules\SupplierManagement\Models\Supplier $account */
$account = $supplier;
}
// Get supplier
if ($supplier->id === 0 && $request->hasData('supplier')) {
$supplier = SupplierMapper::get()
->where('id', $request->getDataInt('supplier'))
->execute();
}
$quantity = new FloatInt($request->getDataString('price_quantity') ?? FloatInt::DIVISOR);
$quantity->value = $quantity->value === 0 ? FloatInt::DIVISOR : $quantity->value;
// Get all relevant prices
$queryMapper = PriceMapper::getAll();
$queryMapper = PriceMapper::getAll()
->where('status', PriceStatus::ACTIVE);
if ($request->hasData('price_name')) {
$queryMapper->where('name', $request->getData('price_name'));
$queryMapper->where('name', $request->getData('name'));
}
$queryMapper->where('promocode', \array_unique([$request->getData('price_promocode'), null]), 'IN');
$queryMapper->where('promocode', \array_unique([$request->getDataString('promocode') ?? '', '']), 'IN');
$queryMapper->where('item', \array_unique([$request->getData('price_item', 'int'), null]), 'IN');
$queryMapper->where('itemgroup', \array_unique([$request->getData('price_itemgroup', 'int'), $item?->getAttribute('itemgroup')->id, null]), 'IN');
$queryMapper->where('itemsegment', \array_unique([$request->getData('price_itemsegment', 'int'), $item?->getAttribute('itemsegment')->id, null]), 'IN');
$queryMapper->where('itemsection', \array_unique([$request->getData('price_itemsection', 'int'), $item?->getAttribute('itemsection')->id, null]), 'IN');
$queryMapper->where('itemtype', \array_unique([$request->getData('price_itemtype', 'int'), $item?->getAttribute('itemtype')->id, null]), 'IN');
// Item
if ($item->id !== 0) {
$queryMapper->where('item', $item->id);
} elseif ($request->hasData('item')) {
$queryMapper->where('item', $request->getDataInt('item'));
}
$queryMapper->where('client', \array_unique([$request->getData('price_client', 'int'), null]), 'IN');
$queryMapper->where('clientgroup', \array_unique([$request->getData('price_clientgroup', 'int'), $client?->getAttribute('clientgroup')->id, null]), 'IN');
$queryMapper->where('clientsegment', \array_unique([$request->getData('price_clientsegment', 'int'), $client?->getAttribute('clientsegment')->id, null]), 'IN');
$queryMapper->where('clientsection', \array_unique([$request->getData('price_clientsection', 'int'), $client?->getAttribute('clientsection')->id, null]), 'IN');
$queryMapper->where('clienttype', \array_unique([$request->getData('price_clienttype', 'int'), $client?->getAttribute('clienttype')->id, null]), 'IN');
$queryMapper->where('clientcountry', \array_unique([$request->getData('price_clientcountry'), $client?->mainAddress->getCountry(), null]), 'IN');
// Item segment
$itemSegment = [null, $request->getDataInt('item_segment')];
if ($item->getAttribute('segment')->value->id !== 0) {
$itemSegment[] = $item->getAttribute('segment')->value->getValue();
}
$queryMapper->where('itemsegment', \array_unique($itemSegment), 'IN');
$queryMapper->where('supplier', \array_unique([$request->getData('price_supplier', 'int'), null]), 'IN');
$queryMapper->where('unit', \array_unique([$request->getData('price_unit', 'int'), null]), 'IN');
$queryMapper->where('type', $request->getData('price_type', 'int') ?? PriceType::SALES);
$queryMapper->where('currency', \array_unique([$request->getData('price_currency', 'int'), null]), 'IN');
// Item section
$itemSection = [null, $request->getDataInt('item_section')];
if ($item->getAttribute('section')->value->id !== 0) {
$itemSection[] = $item->getAttribute('section')->value->getValue();
}
$queryMapper->where('itemsection', \array_unique($itemSection), 'IN');
// @todo: implement start and end
// Item sales group
$itemSalesGroups = [null, $request->getDataInt('sales_group')];
if ($item->getAttribute('sales_group')->value->id !== 0) {
$itemSalesGroups[] = $item->getAttribute('sales_group')->value->getValue();
}
$queryMapper->where('itemsalesgroup', \array_unique($itemSalesGroups), 'IN');
// Item product group
$itemProductGroups = [null, $request->getDataInt('product_group')];
if ($item->getAttribute('product_group')->value->id !== 0) {
$itemProductGroups[] = $item->getAttribute('product_group')->value->getValue();
}
$queryMapper->where('itemproductgroup', \array_unique($itemProductGroups), 'IN');
// Item product type
$itemProductType = [null, $request->getDataInt('product_type')];
if ($item->getAttribute('product_type')->value->id !== 0) {
$itemProductType[] = $item->getAttribute('product_type')->value->getValue();
}
$queryMapper->where('itemtype', \array_unique($itemProductType), 'IN');
// Client
if ($client->id !== 0) {
$queryMapper->where('client', $client->id);
} elseif ($request->hasData('client')) {
$queryMapper->where('client', $request->getDataInt('client'));
}
// Client segment
$clientSegment = [null, $request->getDataInt('client_segment')];
if ($client->getAttribute('segment')->value->id !== 0) {
$clientSegment[] = $client->getAttribute('segment')->value->getValue();
}
$queryMapper->where('clientsegment', \array_unique($clientSegment), 'IN');
// Client section
$clientSection = [null, $request->getDataInt('client_section')];
if ($client->getAttribute('section')->value->id !== 0) {
$clientSection[] = $client->getAttribute('section')->value->getValue();
}
$queryMapper->where('clientsection', \array_unique($clientSection), 'IN');
// Client group
$clientGroup = [null, $request->getDataInt('client_group')];
if ($client->getAttribute('client_group')->value->id !== 0) {
$clientGroup[] = $client->getAttribute('client_group')->value->getValue();
}
$queryMapper->where('clientgroup', \array_unique($clientGroup), 'IN');
// Client type
$clientType = [null, $request->getDataInt('client_type')];
if ($client->getAttribute('client_type')->value->id !== 0) {
$clientType[] = $client->getAttribute('client_type')->value->getValue();
}
$queryMapper->where('clienttype', \array_unique($clientType), 'IN');
// Client type
$clientCountry = [null, $request->getDataInt('client_region')];
if ($client->mainAddress->id !== 0) {
$clientCountry[] = $client->mainAddress->country;
}
$queryMapper->where('clientcountry', \array_unique($clientCountry), 'IN');
// Supplier
if ($supplier->id !== 0) {
$queryMapper->where('supplier', $supplier->id);
} elseif ($request->hasData('supplier')) {
$queryMapper->where('supplier', $request->getDataInt('supplier'));
}
if ($request->hasData('price_unit')) {
$queryMapper->where('unit', $request->getDataInt('price_unit'));
}
$queryMapper->where('type', $request->getDataInt('price_type') ?? ($supplier->id === 0 ? PriceType::SALES : PriceType::PURCHASE));
if ($request->hasData('currency')) {
$queryMapper->where('currency', $request->getData('currency'));
}
// @todo implement start and end
/*
@todo: implement quantity
@todo implement quantity
if ($request->hasData('price_quantity')) {
$whereQuery = new Where();
$whereQuery->where('quantity', (int) $request->getData('price_quantity'), '<=')
@ -148,12 +230,14 @@ final class ApiPriceController extends Controller
/** @var \Modules\Billing\Models\Price\Price[] $prices */
$prices = $queryMapper->execute();
// Find base price (@todo: probably not a good solution)
$bestBasePrice = null;
// Find base price
$basePrice = null;
foreach ($prices as $price) {
if ($price->price->value !== 0 && $price->priceNew === 0
if (/*$price->priceNew->value > 0 */ // Price could be 0
$price->id !== 0
&& $price->item->id !== 0
&& $price->itemgroup->id === 0
&& $price->itemsalesgroup->id === 0
&& $price->itemproductgroup->id === 0
&& $price->itemsegment->id === 0
&& $price->itemsection->id === 0
&& $price->itemtype->id === 0
@ -163,35 +247,51 @@ final class ApiPriceController extends Controller
&& $price->clientsection->id === 0
&& $price->clienttype->id === 0
&& $price->promocode === ''
&& $price->price->value < ($bestBasePrice?->price->value ?? \PHP_INT_MAX)
&& $price->priceNew->value < ($basePrice?->priceNew->value ?? \PHP_INT_MAX)
) {
$bestBasePrice = $price;
$basePrice = $price;
}
}
// @todo: implement prices which cannot be improved even if there are better prices available (i.e. some customer groups may not get better prices, Dentagen Beispiel)
// alternatively set prices as 'improvable' => which whitelists a price as can be improved or 'alwaysimproces' which always overwrites other prices
$basePrice ??= new NullPrice();
// @todo implement prices which cannot be improved even if there are better prices available
// (i.e. some customer groups may not get better prices, Dentagen Beispiel)
// alternatively set prices as 'improvable' => which whitelists a price as can be improved
// or 'always_improves' which always overwrites other prices
// Find best price
$bestPrice = null;
$bestPrice = $basePrice;
$bestPriceValue = \PHP_INT_MAX;
$discounts = [];
foreach ($prices as $price) {
$newPrice = $bestBasePrice?->price->value ?? \PHP_INT_MAX;
if ($price->price->value < $newPrice) {
$newPrice = $price->price->value;
if ($price->isAdditive && $price->priceNew->value === 0) {
$discounts[] = $price;
}
if ($price->priceNew < $newPrice) {
$newPrice = $price->priceNew;
$newPrice = $bestPrice->price->value ?? $basePrice->price->value;
if ($price->priceNew->value > 0 && $price->priceNew->value < $newPrice) {
$newPrice = $price->priceNew->value;
}
$newPrice -= $price->discount;
$newPrice = (int) ((10000 / $price->discountPercentage) * $newPrice);
$newPrice = (int) (($price->quantity === 0 ? 10000 : $price->quantity) / (10000 + $price->bonus) * $newPrice);
if ($price->priceNew->value > 0 && $price->priceNew->value < $newPrice) {
$newPrice = $price->priceNew->value;
}
// @todo: the calculation above regarding discount and bonus don't consider the purchased quantity.
// If a customer receives 1+1 but purchases 2, then he gets 2+2 (if multiply === true) which is better than 1+1 with multiply false.
// Calculate the price EFFECT (this is the theoretical unit price)
// 1. subtract discount value
// 2. subtract discount percentage
// 3. subtract bonus effect
$newPrice -= $price->discount->value;
$newPrice = (int) ($newPrice - $price->bonus->value / FloatInt::DIVISOR * $price->priceNew->value / $quantity->value);
$newPrice = (int) (((FloatInt::DIVISOR * 100) - $price->discountPercentage->value) / (FloatInt::DIVISOR * 100) * $newPrice);
// @todo If a customer receives 1+1 but purchases 2, then he gets 2+2 (if multiply === true) which is better than 1+1 with multiply false.
// Same goes for amount discounts?
if ($newPrice < $bestPriceValue) {
$bestPriceValue = $newPrice;
@ -199,23 +299,39 @@ final class ApiPriceController extends Controller
}
}
// Get tax definition
/** @var \Modules\Billing\Models\Tax\TaxCombination $tax */
$tax = ($request->getDataInt('price_type') ?? PriceType::SALES) === PriceType::SALES
? TaxCombinationMapper::get()
->where('itemCode', $request->getDataInt('price_item'))
->where('clientCode', $account->getAttribute('client_code')->value->id)
->execute()
: TaxCombinationMapper::get()
->where('itemCode', $request->getDataInt('price_item'))
->where('supplierCode', $account->getAttribute('supplier_code')->value->id)
->execute();
if ($bestPrice->priceNew->value === 0) {
$discounts[] = clone $bestPrice;
$bestPrice = $basePrice;
}
$response->header->set('Content-Type', MimeType::M_JSON, true);
$response->set(
$request->uri->__toString(),
\array_values($prices)
);
// Actual price calculation
$bestActualPriceValue = $bestPrice?->priceNew->value ?? \PHP_INT_MAX;
$discountAmount = $bestPrice->discount->value;
$discountPercentage = $bestPrice->discountPercentage->value;
$bonus = $bestPrice->bonus->value;
foreach ($discounts as $discount) {
$bestActualPriceValue -= $discount->discount->value;
$discountAmount += $discount->discount->value;
$discountPercentage += $discount->discountPercentage->value;
$bonus += $discount->bonus->value;
}
$bestActualPriceValue -= $discountAmount;
$bestActualPriceValue = (int) \round(((FloatInt::DIVISOR * 100) - $discountPercentage) / (FloatInt::DIVISOR * 100) * $bestActualPriceValue, 0);
return [
'basePrice' => $basePrice->priceNew,
'bestPrice' => $bestPrice->priceNew,
'supplier' => $bestPrice->supplier->id,
'bestActualPrice' => new FloatInt($bestActualPriceValue),
'discounts' => $discounts,
'discountPercent' => new FloatInt($discountPercentage),
'discountAmount' => new FloatInt($discountAmount),
'bonus' => new FloatInt($bonus),
];
}
/**
@ -260,31 +376,32 @@ final class ApiPriceController extends Controller
$price->name = $request->getDataString('name') ?? '';
$price->promocode = $request->getDataString('promocode') ?? '';
$price->item = new NullItem((int) $request->getData('item'));
$price->itemgroup = new NullAttributeValue((int) $request->getData('itemgroup'));
$price->itemsegment = new NullAttributeValue((int) $request->getData('itemsegment'));
$price->itemsection = new NullAttributeValue((int) $request->getData('itemsection'));
$price->itemtype = new NullAttributeValue((int) $request->getData('itemtype'));
$price->item = new NullItem((int) $request->getData('item'));
$price->itemsegment = new NullAttributeValue((int) $request->getData('itemsegment'));
$price->itemsection = new NullAttributeValue((int) $request->getData('itemsection'));
$price->itemsalesgroup = new NullAttributeValue((int) $request->getData('itemsalesgroup'));
$price->itemproductgroup = new NullAttributeValue((int) $request->getData('itemproductgroup'));
$price->itemtype = new NullAttributeValue((int) $request->getData('itemtype'));
$price->client = new NullClient((int) $request->getData('client'));
$price->clientgroup = new NullAttributeValue((int) $request->getData('clientgroup'));
$price->clientsegment = new NullAttributeValue((int) $request->getData('clientsegment'));
$price->clientsection = new NullAttributeValue((int) $request->getData('clientsection'));
$price->clientgroup = new NullAttributeValue((int) $request->getData('clientgroup'));
$price->clienttype = new NullAttributeValue((int) $request->getData('clienttype'));
$price->supplier = new NullSupplier((int) $request->getData('supplier'));
$price->unit = (int) $request->getData('unit');
$price->type = $request->getDataInt('type') ?? PriceType::SALES;
$price->quantity = (int) $request->getData('quantity');
$price->price = new FloatInt((int) $request->getData('price'));
$price->priceNew = (int) $request->getData('price_new');
$price->discount = (int) $request->getData('discount');
$price->discountPercentage = (int) $request->getData('discountPercentage');
$price->bonus = (int) $request->getData('bonus');
$price->type = PriceType::tryFromValue($request->getDataInt('type')) ?? PriceType::SALES;
$price->quantity = new FloatInt($request->getDataString('quantity') ?? 0);
$price->price = new FloatInt($request->getDataString('price') ?? 0);
$price->priceNew = new FloatInt($request->getDataString('price_new') ?? 0);
$price->discount = new FloatInt($request->getDataString('discount') ?? 0);
$price->discountPercentage = new FloatInt($request->getDataString('discountPercentage') ?? 0);
$price->bonus = new FloatInt($request->getDataString('bonus') ?? 0);
$price->multiply = $request->getDataBool('multiply') ?? false;
$price->currency = $request->getDataString('currency') ?? ISO4217CharEnum::_EUR;
$price->start = $request->getDataDateTime('start') ?? null;
$price->end = $request->getDataDateTime('end') ?? null;
$price->currency = ISO4217CharEnum::tryFromValue($request->getDataString('currency')) ?? ISO4217CharEnum::_EUR;
$price->start = $request->getDataDateTime('start');
$price->end = $request->getDataDateTime('end');
return $price;
}
@ -296,7 +413,7 @@ final class ApiPriceController extends Controller
*
* @return array<string, bool>
*
* @todo: consider to prevent name 'base'?
* @todo consider to prevent name 'default'?
* Might not be possible because it is used internally as well (see apiItemCreate in ItemManagement)
*
* @since 1.0.0
@ -337,6 +454,22 @@ final class ApiPriceController extends Controller
$old = PriceMapper::get()->where('id', (int) $request->getData('id'))->execute();
$new = $this->updatePriceFromRequest($request, clone $old);
if ($new->name === 'default'
&& $old->priceNew->value !== $new->priceNew->value
) {
/** @var \Modules\ItemManagement\Models\Item $item */
$item = ItemMapper::get()->where('id', $new->item)->execute();
$itemNew = clone $item;
if ($new->type === PriceType::SALES) {
$itemNew->salesPrice = $new->priceNew;
} else {
$itemNew->purchasePrice = $new->priceNew;
}
$this->updateModel($request->header->account, $item, $itemNew, ItemMapper::class, 'price', $request->getOrigin());
}
$this->updateModel($request->header->account, $old, $new, PriceMapper::class, 'price', $request->getOrigin());
$this->createStandardUpdateResponse($request, $response, $new);
}
@ -353,17 +486,19 @@ final class ApiPriceController extends Controller
*/
public function updatePriceFromRequest(RequestAbstract $request, Price $new) : Price
{
$new->name = $new->name !== 'base'
$new->name = $new->name !== 'default'
? ($request->getDataString('name') ?? $new->name)
: $new->name;
$new->status = PriceStatus::tryFromValue($request->getDataInt('type')) ?? $new->status;
$new->promocode = $request->getDataString('promocode') ?? $new->promocode;
$new->item = $request->hasData('item') ? new NullItem((int) $request->getData('item')) : $new->item;
$new->itemgroup = $request->hasData('itemgroup') ? new NullAttributeValue((int) $request->getData('itemgroup')) : $new->itemgroup;
$new->itemsegment = $request->hasData('itemsegment') ? new NullAttributeValue((int) $request->getData('itemsegment')) : $new->itemsegment;
$new->itemsection = $request->hasData('itemsection') ? new NullAttributeValue((int) $request->getData('itemsection')) : $new->itemsection;
$new->itemtype = $request->hasData('itemtype') ? new NullAttributeValue((int) $request->getData('itemtype')) : $new->itemtype;
$new->itemsalesgroup = $request->hasData('itemsalesgroup') ? new NullAttributeValue((int) $request->getData('itemsalesgroup')) : $new->itemsalesgroup;
$new->itemproductgroup = $request->hasData('itemproductgroup') ? new NullAttributeValue((int) $request->getData('itemproductgroup')) : $new->itemproductgroup;
$new->itemsegment = $request->hasData('itemsegment') ? new NullAttributeValue((int) $request->getData('itemsegment')) : $new->itemsegment;
$new->itemsection = $request->hasData('itemsection') ? new NullAttributeValue((int) $request->getData('itemsection')) : $new->itemsection;
$new->itemtype = $request->hasData('itemtype') ? new NullAttributeValue((int) $request->getData('itemtype')) : $new->itemtype;
$new->client = $request->hasData('client') ? new NullClient((int) $request->getData('client')) : $new->client;
$new->clientgroup = $request->hasData('clientgroup') ? new NullAttributeValue((int) $request->getData('clientgroup')) : $new->clientgroup;
@ -373,15 +508,16 @@ final class ApiPriceController extends Controller
$new->supplier = $request->hasData('supplier') ? new NullSupplier((int) $request->getData('supplier')) : $new->supplier;
$new->unit = $request->getDataInt('unit') ?? $new->unit;
$new->type = $request->getDataInt('type') ?? $new->type;
$new->quantity = $request->getDataInt('quantity') ?? $new->quantity;
$new->price = $request->hasData('price') ? new FloatInt((int) $request->getData('price')) : $new->price;
$new->priceNew = $request->getDataInt('price_new') ?? $new->priceNew;
$new->discount = $request->getDataInt('discount') ?? $new->discount;
$new->discountPercentage = $request->getDataInt('discountPercentage') ?? $new->discountPercentage;
$new->bonus = $request->getDataInt('bonus') ?? $new->bonus;
$new->quantity = new FloatInt($request->getDataString('quantity') ?? $new->quantity->value);
$new->price = new FloatInt($request->getDataString('price') ?? $new->price->value);
$new->priceNew = new FloatInt($request->getDataString('price_new') ?? $new->priceNew->value);
$new->discount = new FloatInt($request->getDataString('discount') ?? $new->discount->value);
$new->discountPercentage = new FloatInt($request->getDataString('discountPercentage') ?? $new->discountPercentage->value);
$new->bonus = new FloatInt($request->getDataString('bonus') ?? $new->bonus->value);
$new->multiply = $request->getDataBool('multiply') ?? $new->multiply;
$new->currency = $request->getDataString('currency') ?? $new->currency;
$new->currency = ISO4217CharEnum::tryFromValue($request->getDataString('currency')) ?? $new->currency;
$new->start = $request->getDataDateTime('start') ?? $new->start;
$new->end = $request->getDataDateTime('end') ?? $new->end;
@ -395,9 +531,6 @@ final class ApiPriceController extends Controller
*
* @return array<string, bool>
*
* @todo: implement
* @todo: consider to block 'base' name
*
* @since 1.0.0
*/
private function validatePriceUpdate(RequestAbstract $request) : array
@ -435,7 +568,7 @@ final class ApiPriceController extends Controller
/** @var \Modules\Billing\Models\Price\Price $price */
$price = PriceMapper::get()->where('id', (int) $request->getData('id'))->execute();
if ($price->name === 'base') {
if ($price->name === 'default') {
// default price cannot be deleted
$this->createInvalidDeleteResponse($request, $response, []);

View File

@ -1,5 +1,4 @@
<?php
/**
* Jingga
*
@ -15,18 +14,19 @@ declare(strict_types=1);
namespace Modules\Billing\Controller;
use Modules\Billing\Models\BillMapper;
use Modules\Billing\Models\BillStatus;
use Modules\Billing\Models\BillTransferType;
use Modules\Billing\Models\BillTypeMapper;
use Modules\Billing\Models\SettingsEnum;
use phpOMS\Message\Http\HttpRequest;
use phpOMS\Message\Http\HttpResponse;
use phpOMS\Message\Http\RequestStatusCode;
use phpOMS\Message\RequestAbstract;
use phpOMS\Message\ResponseAbstract;
use phpOMS\System\OperatingSystem;
use phpOMS\System\SystemType;
use phpOMS\System\SystemUtils;
use phpOMS\Uri\HttpUri;
/**
* Billing class.
@ -51,17 +51,56 @@ final class ApiPurchaseController extends Controller
*
* @throws \Exception
*
* apiSupplierBillUpload
* -> apiBillCreate
* -> [createBill]
* -> apiMediaAddToBill
* -> apiInvoiceParse
* -> cliParseSupplierBill
* -> [updateBill]
* -> apiBillPdfArchiveCreate
* -> eventBillArchive
*
* @since 1.0.0
*/
public function apiSupplierBillUpload(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
if (!empty($val = $this->validateSupplierBillUpload($request))) {
$response->header->status = RequestStatusCode::R_400;
$this->createInvalidCreateResponse($request, $response, $val);
return;
}
$bills = $this->createSupplierBillUploadFromRequest($request, $response, $data);
if (empty($bills)) {
$response->header->status = RequestStatusCode::R_400;
$this->createInvalidCreateResponse($request, $response, $val);
}
$this->createStandardCreateResponse($request, $response, $bills);
}
/**
* Method to create item attribute from request.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return array
*
* @since 1.0.0
*/
private function createSupplierBillUploadFromRequest(RequestAbstract $request, ResponseAbstract $response, $data) : array
{
/** @var \Model\Setting $setting */
$setting = $this->app->appSettings->get(
names: SettingsEnum::ORIGINAL_MEDIA_TYPE,
names: SettingsEnum::EXTERNAL_MEDIA_TYPE,
module: self::NAME
);
$originalType = $request->getDataInt('type') ?? ((int) $setting->content);
$internalType = $request->getDataInt('type') ?? ((int) $setting->content);
/** @var \Modules\Billing\Models\BillType $purchaseTransferType */
$purchaseTransferType = BillTypeMapper::get()
@ -69,10 +108,12 @@ final class ApiPurchaseController extends Controller
->limit(1)
->execute();
$files = $request->files;
$bills = [];
$files = \array_merge($request->files, $request->getDataJson('media'));
foreach ($files as $file) {
// Create default bill
$billRequest = new HttpRequest(new HttpUri(''));
$billRequest = new HttpRequest();
$billRequest->header->account = $request->header->account;
$billRequest->header->l11n = $request->header->l11n;
$billRequest->setData('supplier', 0);
@ -82,61 +123,150 @@ final class ApiPurchaseController extends Controller
$billResponse = new HttpResponse();
$billResponse->header->l11n = $response->header->l11n;
$this->app->moduleManager->get('Billing', 'Api')->apiBillCreate($billRequest, $billResponse, $data);
$this->app->moduleManager->get('Billing', 'ApiBill')->apiBillCreate($billRequest, $billResponse, $data);
$billId = $billResponse->getDataArray('')['response']->id;
$billId = $billResponse->getDataArray('')['response']->id;
$bills[] = $billId;
// Upload and assign document to bill
$mediaRequest = new HttpRequest();
$mediaRequest->header->account = $request->header->account;
$mediaRequest->header->l11n = $request->header->l11n;
$mediaRequest->addFile($file);
$mediaResponse = new HttpResponse();
$mediaRequest = new HttpRequest();
$mediaResponse = new HttpResponse();
$mediaResponse->header->l11n = $response->header->l11n;
$mediaRequest->header->account = $request->header->account;
$mediaRequest->header->l11n = $request->header->l11n;
if (\is_array($file)) {
$mediaRequest->addFile($file);
} else {
$mediaRequest->setData('media', \json_encode($file));
}
$mediaRequest->setData('bill', $billId);
$mediaRequest->setData('type', $originalType);
$mediaRequest->setData('type', $internalType);
$mediaRequest->setData('parse_content', true, true);
$this->app->moduleManager->get('Billing', 'Api')->apiMediaAddToBill($mediaRequest, $mediaResponse, $data);
$this->app->moduleManager->get('Billing', 'ApiBill')->apiMediaAddToBill($mediaRequest, $mediaResponse, $data);
/** @var \Modules\Media\Models\Media[] $uploaded */
$uploaded = $mediaResponse->getDataArray('')['response']['upload'];
if (empty($uploaded)) {
throw new \Exception();
if (\is_array($file)) {
/** @var \Modules\Media\Models\Media[] $uploaded */
$uploaded = $mediaResponse->getDataArray('')['response']['upload'];
if (empty($uploaded)) {
return [];
}
$in = \reset($uploaded)->getAbsolutePath();
if (!\is_file($in)) {
return [];
}
}
$in = \reset($uploaded)->getAbsolutePath(); // pdf parsed content is available in $in->content
if (!\is_file($in)) {
throw new \Exception();
}
$request->setData('id', $billId, true);
$request->setData('bill', $billId, true);
// Create internal document
$billResponse = new HttpResponse();
$billRequest = new HttpRequest(new HttpUri(''));
$billRequest->header->account = $request->header->account;
$billRequest->setData('bill', $billId);
$this->app->moduleManager->get('Billing', 'Api')->apiBillPdfArchiveCreate($billRequest, $billResponse);
// Offload bill parsing to cli
$cliPath = \realpath(__DIR__ . '/../../../cli.php');
if ($cliPath === false) {
return;
}
try {
SystemUtils::runProc(
OperatingSystem::getSystem() === SystemType::WIN ? 'php.exe' : 'php',
\escapeshellarg($cliPath)
. ' /billing/bill/purchase/parse '
. '-i ' . \escapeshellarg((string) $billId),
true
);
} catch (\Throwable $t) {
$this->app->logger->error($t->getMessage());
}
$this->apiInvoiceParse($request, $response, $data);
}
return $bills;
}
/**
* Validate item attribute create request
*
* @param RequestAbstract $request Request
*
* @return array<string, bool>
*
* @since 1.0.0
*/
private function validateSupplierBillUpload(RequestAbstract $request) : array
{
$val = [];
if (($val['files'] = empty($request->files))) {
return $val;
}
return [];
}
/**
* Api method to create bill files
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @throws \Exception
*
* @since 1.0.0
*/
public function apiInvoiceParse(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
if (!empty($val = $this->validateInvoiceParse($request))) {
$response->header->status = RequestStatusCode::R_400;
$this->createInvalidCreateResponse($request, $response, $val);
return;
}
$bill = BillMapper::get()
->where('id', (int) $request->getData('id'))
->execute();
// After a bill is "closed" its values shouldn't change
if ($bill->status !== BillStatus::DRAFT
&& $bill->status !== BillStatus::UNPARSED
&& $bill->status !== BillStatus::ACTIVE
) {
$response->header->status = RequestStatusCode::R_423;
$this->createInvalidCreateResponse($request, $response, $val);
return;
}
// Offload bill parsing to cli
$cliPath = \realpath(__DIR__ . '/../../../cli.php');
if ($cliPath === false) {
return;
}
try {
SystemUtils::runProc(
OperatingSystem::getSystem() === SystemType::WIN ? 'php.exe' : 'php',
'-dxdebug.remote_enable=1 -dxdebug.start_with_request=yes -dxdebug.mode=coverage,develop,debug ' .
\escapeshellarg($cliPath)
. ' /billing/bill/purchase/parse '
. '-i ' . \escapeshellarg((string) $bill->id),
$request->getDataBool('async') ?? true
);
} catch (\Throwable $t) {
$response->header->status = RequestStatusCode::R_400;
$this->app->logger->error($t->getMessage());
}
$this->createStandardUpdateResponse($request, $response, $bill);
}
/**
* Validate item attribute create request
*
* @param RequestAbstract $request Request
*
* @return array<string, bool>
*
* @since 1.0.0
*/
private function validateInvoiceParse(RequestAbstract $request) : array
{
$val = [];
if (($val['id'] = !$request->hasData('id'))) {
return $val;
}
return [];
}
}

View File

@ -14,22 +14,25 @@ declare(strict_types=1);
namespace Modules\Billing\Controller;
use Modules\Admin\Models\Address;
use Modules\Attribute\Models\AttributeValue;
use Modules\Attribute\Models\NullAttributeValue;
use Modules\Billing\Models\Tax\NullTaxCombination;
use Modules\Billing\Models\Tax\TaxCombination;
use Modules\Billing\Models\Tax\TaxCombinationMapper;
use Modules\ClientManagement\Models\Attribute\ClientAttributeTypeMapper;
use Modules\ClientManagement\Models\Client;
use Modules\Finance\Models\TaxCode;
use Modules\Finance\Models\NullTaxCode;
use Modules\Finance\Models\TaxCodeMapper;
use Modules\ItemManagement\Models\Item;
use Modules\Organization\Models\UnitMapper;
use phpOMS\Localization\ISO3166CharEnum;
use Modules\SupplierManagement\Models\Attribute\SupplierAttributeTypeMapper;
use Modules\SupplierManagement\Models\Supplier;
use phpOMS\Localization\ISO3166TwoEnum;
use phpOMS\Message\Http\RequestStatusCode;
use phpOMS\Message\RequestAbstract;
use phpOMS\Message\ResponseAbstract;
use phpOMS\Security\Guard;
use phpOMS\Stdlib\Base\Address;
/**
* Billing class.
@ -44,32 +47,49 @@ final class ApiTaxController extends Controller
/**
* Get tax code from client and item.
*
* @param Client $client Client to get tax code from
* @param Item $item Item toget tax code from
* @param string $defaultCountry default country to use if no valid tax code could be found and if the unit country code shouldn't be used
* @param Item $item Item to get tax code from
* @param null|Client $client Client to get tax code from
* @param null|Supplier $supplier Supplier to get tax code from
* @param string $defaultCountry Default country to use if no valid tax code could be found
* and if the unit country code shouldn't be used
*
* @return TaxCode
* @return TaxCombination
*
* @since 1.0.0
*/
public function getTaxCodeFromClientItem(Client $client, Item $item, string $defaultCountry = '') : TaxCode
public function getTaxForPerson(
Item $item,
?Client $client = null, ?Supplier $supplier = null,
string $defaultCountry = ''
) : TaxCombination
{
// @todo: define default sales tax code if none available?!
// @todo: consider to actually use a ownsOne reference instead of only a string, this way the next line with the TaxCodeMapper can be removed
if ($client === null && $supplier === null) {
return new NullTaxCombination();
}
// @todo define default sales tax code if none available?!
$itemCode = 0;
$accountCode = 0;
$combinationType = 'clientCode';
if ($client !== null) {
$itemCode = $item->getAttribute('sales_tax_code')->value->id;
$accountCode = $client->getAttribute('sales_tax_code')->value->id;
} else {
$itemCode = $item->getAttribute('purchase_tax_code')->value->id;
$accountCode = $supplier->getAttribute('purchase_tax_code')->value->id;
$combinationType = 'supplierCode';
}
/** @var \Modules\Billing\Models\Tax\TaxCombination $taxCombination */
$taxCombination = TaxCombinationMapper::get()
->where('itemCode', $item->getAttribute('sales_tax_code')->value->id)
->where('clientCode', $client->getAttribute('sales_tax_code')->value->id)
->with('taxCode')
->where('itemCode', $itemCode)
->where($combinationType, $accountCode)
->execute();
/** @var \Modules\Finance\Models\TaxCode $taxCode */
$taxCode = TaxCodeMapper::get()
->where('abbr', $taxCombination->taxCode)
->execute();
if ($taxCode->id !== 0) {
return $taxCode;
if ($taxCombination->taxCode->id !== 0) {
return $taxCombination;
}
/** @var \Modules\Organization\Models\Unit $unit */
@ -78,28 +98,23 @@ final class ApiTaxController extends Controller
->where('id', $this->app->unitId)
->execute();
// Create dummy client
$client = new Client();
$client->mainAddress = $unit->mainAddress;
// Create dummy
$account = $client !== null ? new Client() : new Supplier();
$account->mainAddress = $unit->mainAddress;
if (!empty($defaultCountry)) {
$client->mainAddress->setCountry($defaultCountry);
$account->mainAddress->setCountry($defaultCountry);
}
$taxCodeAttribute = $this->getClientTaxCode($client, $unit->mainAddress);
$taxCodeAttribute = $client !== null
? $this->getClientTaxCode($account, $unit->mainAddress)
: $this->getSupplierTaxCode($account, $unit->mainAddress);
/** @var \Modules\Billing\Models\Tax\TaxCombination $taxCombination */
$taxCombination = TaxCombinationMapper::get()
->where('itemCode', $item->getAttribute('sales_tax_code')->value->id)
->where('clientCode', $taxCodeAttribute->id)
return TaxCombinationMapper::get()
->with('taxCode')
->where('itemCode', $itemCode)
->where($combinationType, $taxCodeAttribute->id)
->execute();
/** @var \Modules\Finance\Models\TaxCode $taxCode */
$taxCode = TaxCodeMapper::get()
->where('abbr', $taxCombination->taxCode)
->execute();
return $taxCode;
}
/**
@ -138,10 +153,11 @@ final class ApiTaxController extends Controller
*/
private function createTaxCombinationFromRequest(RequestAbstract $request) : TaxCombination
{
$tax = new TaxCombination();
$tax->taxType = $request->getDataInt('tax_type') ?? 1;
$tax->taxCode = (string) $request->getData('tax_code');
$tax->itemCode = new NullAttributeValue((int) $request->getData('item_code'));
$tax = new TaxCombination();
$tax->taxType = $request->getDataInt('tax_type') ?? 1;
$tax->taxCode->abbr = (string) $request->getData('tax_code');
$tax->itemCode = new NullAttributeValue((int) $request->getData('item_code'));
$tax->account = $request->getDataString('account') ?? '';
if ($tax->taxType === 1) {
$tax->clientCode = new NullAttributeValue((int) $request->getData('account_code'));
@ -195,28 +211,72 @@ final class ApiTaxController extends Controller
$taxCode = new NullAttributeValue();
// @todo: need to consider own tax id as well
if ($taxOfficeAddress->getCountry() === $client->mainAddress->getCountry()) {
$taxCode = $codes->getDefaultByValue($client->mainAddress->getCountry());
} elseif (\in_array($taxOfficeAddress->getCountry(), ISO3166CharEnum::getRegion('eu'))
&& \in_array($client->mainAddress->getCountry(), ISO3166CharEnum::getRegion('eu'))
// @todo need to consider own tax id as well
// @todo consider delivery & invoice location (Reihengeschaeft)
if ($taxOfficeAddress->country === $client->mainAddress->country) {
// Same country as we (= local tax code)
return $codes->getDefaultByValue($client->mainAddress->country);
} elseif (\in_array($taxOfficeAddress->country, ISO3166TwoEnum::getRegion('eu'))
&& \in_array($client->mainAddress->country, ISO3166TwoEnum::getRegion('eu'))
) {
if (!empty($client->getAttribute('vat_id')->value->getValue())) {
// Is EU company
$taxCode = $codes->getDefaultByValue('EU');
// Is EU company and we are EU company
return $codes->getDefaultByValue('EU');
} else {
// Is EU private customer
$taxCode = $codes->getDefaultByValue($client->mainAddress->getCountry());
// Is EU private customer and we are EU company
return $codes->getDefaultByValue($client->mainAddress->country);
}
} elseif (\in_array($taxOfficeAddress->getCountry(), ISO3166CharEnum::getRegion('eu'))) {
} elseif (\in_array($taxOfficeAddress->country, ISO3166TwoEnum::getRegion('eu'))) {
// None EU company but we are EU company
$taxCode = $codes->getDefaultByValue('INT');
} else {
// None EU company and we are also none EU company
$taxCode = $codes->getDefaultByValue('INT');
return $codes->getDefaultByValue('INT');
}
return $taxCode;
// None EU company and we are also none EU company
return $codes->getDefaultByValue('INT');
}
/**
* Get the supplier's tax code based on their country and tax office address
*
* @param Supplier $supplier The supplier to get the tax code for
* @param Address $taxOfficeAddress The tax office address used to determine the tax code
*
* @return AttributeValue The supplier's tax code
*
* @since 1.0.0
*/
public function getSupplierTaxCode(Supplier $supplier, Address $taxOfficeAddress) : AttributeValue
{
/** @var \Modules\Attribute\Models\AttributeType $codes */
$codes = SupplierAttributeTypeMapper::get()
->with('defaults')
->where('name', 'purchase_tax_code')
->execute();
$taxCode = new NullAttributeValue();
// @todo need to consider own tax id as well
// @todo consider delivery & invoice location (Reihengeschaeft)
if ($taxOfficeAddress->country === $supplier->mainAddress->country) {
// Same country as we (= local tax code)
return $codes->getDefaultByValue($supplier->mainAddress->country);
} elseif (\in_array($taxOfficeAddress->country, ISO3166TwoEnum::getRegion('eu'))
&& \in_array($supplier->mainAddress->country, ISO3166TwoEnum::getRegion('eu'))
) {
if (!empty($supplier->getAttribute('vat_id')->value->getValue())) {
// Is EU company and we are EU company
return $codes->getDefaultByValue('EU');
} else {
// Is EU private customer and we are EU company
return $codes->getDefaultByValue($supplier->mainAddress->country);
}
} elseif (\in_array($taxOfficeAddress->country, ISO3166TwoEnum::getRegion('eu'))) {
// None EU company but we are EU company
return $codes->getDefaultByValue('INT');
}
// None EU company and we are also none EU company
return $codes->getDefaultByValue('INT');
}
/**
@ -307,7 +367,7 @@ final class ApiTaxController extends Controller
$old = \reset($old);
$new = clone $old;
$new->taxCode = $combination['tax_code'] ?? '';
$new->taxCode = TaxCodeMapper::get()->where('abbr', $combination['tax_code'] ?? '')->execute();
$this->updateModel($request->header->account, $old, $new, TaxCombinationMapper::class, 'tax_combination', $request->getOrigin());
}
@ -347,7 +407,7 @@ final class ApiTaxController extends Controller
public function updateTaxCombinationFromRequest(RequestAbstract $request, TaxCombination $new) : TaxCombination
{
$new->taxType = $request->getDataInt('tax_type') ?? $new->taxType;
$new->taxCode = $request->getDataString('tax_code') ?? $new->taxCode;
$new->taxCode = $request->hasData('tax_code') ? new NullTaxCode((int) $request->getData('tax_code')) : $new->taxCode;
$new->itemCode = $request->hasData('item_code') ? new NullAttributeValue((int) $request->getData('item_code')) : $new->itemCode;
if ($new->taxType === 1) {
@ -413,8 +473,6 @@ final class ApiTaxController extends Controller
*
* @return array<string, bool>
*
* @todo: implement
*
* @since 1.0.0
*/
private function validateTaxCombinationDelete(RequestAbstract $request) : array

View File

@ -20,15 +20,18 @@ use Modules\Billing\Models\BillMapper;
use Modules\Billing\Models\BillStatus;
use Modules\Billing\Models\BillTransferType;
use Modules\Billing\Models\BillTypeMapper;
use Modules\Billing\Models\PaymentTermL11nMapper;
use Modules\Billing\Models\PaymentTermMapper;
use Modules\Billing\Models\PermissionCategory;
use Modules\Billing\Models\PurchaseBillMapper;
use Modules\Billing\Models\SalesBillMapper;
use Modules\Billing\Models\SettingsEnum;
use Modules\Billing\Models\ShippingTermL11nMapper;
use Modules\Billing\Models\ShippingTermMapper;
use Modules\Billing\Models\StockBillMapper;
use phpOMS\Asset\AssetType;
use phpOMS\Account\PermissionType;
use phpOMS\Contract\RenderableInterface;
use phpOMS\DataStorage\Database\Query\OrderType;
use phpOMS\Localization\ISO3166CharEnum;
use phpOMS\Localization\ISO3166NameEnum;
use phpOMS\Message\RequestAbstract;
use phpOMS\Message\ResponseAbstract;
use phpOMS\Utils\StringUtils;
@ -46,7 +49,7 @@ use phpOMS\Views\View;
final class BackendController extends Controller
{
/**
* Routing end-point for application behaviour.
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
@ -67,9 +70,11 @@ final class BackendController extends Controller
->with('type')
->with('type/l11n')
->with('client')
->where('status', BillStatus::DRAFT)
->where('type/transferType', BillTransferType::SALES)
->where('type/l11n/language', $response->header->l11n->language)
->sort('id', OrderType::DESC)
->where('unit', $this->app->unitId)
->limit(25);
if ($request->getData('ptype') === 'p') {
@ -91,7 +96,54 @@ final class BackendController extends Controller
}
/**
* Routing end-point for application behaviour.
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return RenderableInterface
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function viewBillingSalesArchive(RequestAbstract $request, ResponseAbstract $response, array $data = []) : RenderableInterface
{
$view = new View($this->app->l11nManager, $request, $response);
$view->setTemplate('/Modules/Billing/Theme/Backend/sales-bill-list');
$view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1005104001, $request, $response);
$mapperQuery = SalesBillMapper::getAll()
->with('type')
->with('type/l11n')
->with('client')
->where('status', BillStatus::DRAFT, '!=')
->where('type/transferType', BillTransferType::SALES)
->where('type/l11n/language', $response->header->l11n->language)
->sort('id', OrderType::DESC)
->where('unit', $this->app->unitId)
->limit(25);
if ($request->getData('ptype') === 'p') {
$view->data['bills'] = $mapperQuery
->where('id', $request->getDataInt('id') ?? 0, '<')
->where('client', null, '!=')
->execute();
} elseif ($request->getData('ptype') === 'n') {
$view->data['bills'] = $mapperQuery->where('id', $request->getDataInt('id') ?? 0, '>')
->where('client', null, '!=')
->execute();
} else {
$view->data['bills'] = $mapperQuery->where('id', 0, '>')
->where('client', null, '!=')
->execute();
}
return $view;
}
/**
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
@ -112,6 +164,7 @@ final class BackendController extends Controller
$bill = SalesBillMapper::get()
->with('client')
->with('elements')
->with('elements/container')
->with('files')
->with('files/types')
->with('notes')
@ -120,31 +173,53 @@ final class BackendController extends Controller
$view->data['bill'] = $bill;
/** @var \Modules\Auditor\Models\Audit[] $logsBill */
$logsBill = AuditMapper::getAll()
->with('createdBy')
->where('module', 'Billing')
->where('type', StringUtils::intHash(BillMapper::class))
->where('ref', $bill->id)
$billTypes = BillTypeMapper::getAll()
->with('l11n')
->where('isTemplate', false)
->where('transferType', BillTransferType::SALES)
->where('l11n/language', $request->header->l11n->language)
->execute();
/** @var \Modules\Auditor\Models\Audit[] $logsElements */
$logsElements = AuditMapper::getAll()
->with('createdBy')
->where('module', 'Billing')
->where('type', StringUtils::intHash(BillElementMapper::class))
->where('ref', \array_keys($bill->getElements()), 'IN')
->execute();
$view->data['billtypes'] = $billTypes;
$logs = \array_merge($logsBill, $logsElements);
$logs = [];
if ($this->app->accountManager->get($request->header->account)->hasPermission(
PermissionType::READ,
$this->app->unitId,
null,
self::NAME,
PermissionCategory::BILL_LOG,
)
) {
/** @var \Modules\Auditor\Models\Audit[] $logs */
$logs = AuditMapper::getAll()
->with('createdBy')
->where('module', 'Billing')
->where('type', StringUtils::intHash(BillMapper::class))
->where('ref', $bill->id)
->execute();
$view->data['logs'] = $logs;
if (!empty($bill->elements)) {
/** @var \Modules\Auditor\Models\Audit[] $logsElements */
$logsElements = AuditMapper::getAll()
->with('createdBy')
->where('module', 'Billing')
->where('type', StringUtils::intHash(BillElementMapper::class))
->where('ref', \array_keys($bill->elements), 'IN')
->execute();
$logs = \array_merge($logs, $logsElements);
}
}
$view->data['logs'] = $logs;
$view->data['media-upload'] = new \Modules\Media\Theme\Backend\Components\Upload\BaseView($this->app->l11nManager, $request, $response);
return $view;
}
/**
* Routing end-point for application behaviour.
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
@ -170,15 +245,13 @@ final class BackendController extends Controller
$view->data['billtypes'] = $billTypes;
$mediaListView = new \Modules\Media\Theme\Backend\Components\Media\ListView($this->app->l11nManager, $request, $response);
$mediaListView->setTemplate('/Modules/Media/Theme/Backend/Components/Media/list');
$view->data['medialist'] = $mediaListView;
$view->data['media-upload'] = new \Modules\Media\Theme\Backend\Components\Upload\BaseView($this->app->l11nManager, $request, $response);
return $view;
}
/**
* Routing end-point for application behaviour.
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
@ -199,7 +272,7 @@ final class BackendController extends Controller
}
/**
* Routing end-point for application behaviour.
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
@ -220,7 +293,7 @@ final class BackendController extends Controller
}
/**
* Routing end-point for application behaviour.
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
@ -243,6 +316,7 @@ final class BackendController extends Controller
->with('supplier')
->where('type/transferType', BillTransferType::PURCHASE)
->sort('id', OrderType::DESC)
->where('unit', $this->app->unitId)
->limit(25);
if ($request->getData('ptype') === 'p') {
@ -267,7 +341,7 @@ final class BackendController extends Controller
}
/**
* Routing end-point for application behaviour.
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
@ -284,37 +358,61 @@ final class BackendController extends Controller
$view->setTemplate('/Modules/Billing/Theme/Backend/purchase-bill');
$view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1005105001, $request, $response);
$bill = PurchaseBillMapper::get()
$view->data['bill'] = PurchaseBillMapper::get()
->with('supplier')
->with('elements')
->with('elements/container')
->with('files')
->with('files/types')
->with('notes')
->where('id', (int) $request->getData('id'))
->execute();
$view->data['bill'] = $bill;
$view->data['billtypes'] = BillTypeMapper::getAll()
->with('l11n')
->where('isTemplate', false)
->where('transferType', BillTransferType::PURCHASE)
->where('l11n/language', $request->header->l11n->language)
->execute();
/** @var \Model\Setting $previewType */
$previewType = $this->app->appSettings->get(
names: SettingsEnum::PREVIEW_MEDIA_TYPE,
module: self::NAME
);
$logs = [];
if ($this->app->accountManager->get($request->header->account)->hasPermission(
PermissionType::READ,
$this->app->unitId,
null,
self::NAME,
PermissionCategory::BILL_LOG,
)
) {
/** @var \Modules\Auditor\Models\Audit[] $logs */
$logs = AuditMapper::getAll()
->with('createdBy')
->where('module', 'Billing')
->where('type', StringUtils::intHash(BillMapper::class))
->where('ref', $view->data['bill']->id)
->execute();
$view->data['previewType'] = (int) $previewType->content;
if (!empty($view->data['bill']->elements)) {
/** @var \Modules\Auditor\Models\Audit[] $logsElements */
$logsElements = AuditMapper::getAll()
->with('createdBy')
->where('module', 'Billing')
->where('type', StringUtils::intHash(BillElementMapper::class))
->where('ref', \array_keys($view->data['bill']->elements), 'IN')
->execute();
/** @var \Model\Setting $originalType */
$originalType = $this->app->appSettings->get(
names: SettingsEnum::ORIGINAL_MEDIA_TYPE,
module: self::NAME
);
$logs = \array_merge($logs, $logsElements);
}
}
$view->data['originalType'] = (int) $originalType->content;
$view->data['logs'] = $logs;
$view->data['media-upload'] = new \Modules\Media\Theme\Backend\Components\Upload\BaseView($this->app->l11nManager, $request, $response);
return $view;
}
/**
* Routing end-point for application behaviour.
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
@ -332,18 +430,18 @@ final class BackendController extends Controller
$view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1005106001, $request, $response);
if ($request->getData('ptype') === 'p') {
$view->data['bills'] = StockBillMapper::getAll()->where('id', $request->getDataInt('id') ?? 0, '<')->limit(25)->execute();
$view->data['bills'] = StockBillMapper::getAll()->where('id', $request->getDataInt('id') ?? 0, '<')->where('unit', $this->app->unitId)->limit(25)->execute();
} elseif ($request->getData('ptype') === 'n') {
$view->data['bills'] = StockBillMapper::getAll()->where('id', $request->getDataInt('id') ?? 0, '>')->limit(25)->execute();
$view->data['bills'] = StockBillMapper::getAll()->where('id', $request->getDataInt('id') ?? 0, '>')->where('unit', $this->app->unitId)->limit(25)->execute();
} else {
$view->data['bills'] = StockBillMapper::getAll()->where('id', 0, '>')->limit(25)->execute();
$view->data['bills'] = StockBillMapper::getAll()->where('id', 0, '>')->where('unit', $this->app->unitId)->limit(25)->execute();
}
return $view;
}
/**
* Routing end-point for application behaviour.
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
@ -362,13 +460,14 @@ final class BackendController extends Controller
$bill = StockBillMapper::get()->where('id', (int) $request->getData('id'))->execute();
$view->data['bill'] = $bill;
$view->data['bill'] = $bill;
$view->data['media-upload'] = new \Modules\Media\Theme\Backend\Components\Upload\BaseView($this->app->l11nManager, $request, $response);
return $view;
}
/**
* Routing end-point for application behaviour.
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
@ -389,7 +488,7 @@ final class BackendController extends Controller
}
/**
* Routing end-point for application behaviour.
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
@ -410,7 +509,7 @@ final class BackendController extends Controller
}
/**
* Routing end-point for application behaviour.
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
@ -424,7 +523,7 @@ final class BackendController extends Controller
public function viewPrivatePurchaseBillDashboard(RequestAbstract $request, ResponseAbstract $response, array $data = []) : RenderableInterface
{
$view = new View($this->app->l11nManager, $request, $response);
$view->setTemplate('/Modules/Billing/Theme/Backend/user-purchase-bill-dashboard');
$view->setTemplate('/Modules/Billing/Theme/Backend/purchase-bill-list');
$view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1005109001, $request, $response);
$mapperQuery = PurchaseBillMapper::getAll()
@ -434,6 +533,7 @@ final class BackendController extends Controller
->where('type/transferType', BillTransferType::PURCHASE)
->where('status', BillStatus::UNPARSED)
->sort('id', OrderType::DESC)
->where('unit', $this->app->unitId)
->limit(25);
if ($request->getData('ptype') === 'p') {
@ -455,7 +555,7 @@ final class BackendController extends Controller
}
/**
* Routing end-point for application behaviour.
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
@ -469,7 +569,7 @@ final class BackendController extends Controller
public function viewPrivateBillingPurchaseInvoice(RequestAbstract $request, ResponseAbstract $response, array $data = []) : RenderableInterface
{
$view = new View($this->app->l11nManager, $request, $response);
$view->setTemplate('/Modules/Billing/Theme/Backend/user-purchase-bill');
$view->setTemplate('/Modules/Billing/Theme/Backend/purchase-bill');
$view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1005109001, $request, $response);
$bill = PurchaseBillMapper::get()
@ -490,13 +590,138 @@ final class BackendController extends Controller
$view->data['previewType'] = (int) $previewType->content;
/** @var \Model\Setting $originalType */
$originalType = $this->app->appSettings->get(
names: SettingsEnum::ORIGINAL_MEDIA_TYPE,
/** @var \Model\Setting $externalType */
$externalType = $this->app->appSettings->get(
names: SettingsEnum::EXTERNAL_MEDIA_TYPE,
module: self::NAME
);
$view->data['originalType'] = (int) $originalType->content;
$view->data['externalType'] = (int) $externalType->content;
$view->data['media-upload'] = new \Modules\Media\Theme\Backend\Components\Upload\BaseView($this->app->l11nManager, $request, $response);
return $view;
}
/**
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return RenderableInterface
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function viewPaymentList(RequestAbstract $request, ResponseAbstract $response, array $data = []) : RenderableInterface
{
$view = new View($this->app->l11nManager, $request, $response);
$view->setTemplate('/Modules/Billing/Theme/Backend/payment-type-list');
$view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1002901101, $request, $response);
$view->data['types'] = PaymentTermMapper::getAll()
->with('l11n')
->where('l11n/language', $response->header->l11n->language)
->execute();
return $view;
}
/**
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return RenderableInterface
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function viewPaymentView(RequestAbstract $request, ResponseAbstract $response, array $data = []) : RenderableInterface
{
$view = new View($this->app->l11nManager, $request, $response);
$view->setTemplate('/Modules/Billing/Theme/Backend/payment-view');
$view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1002901101, $request, $response);
$view->data['type'] = PaymentTermMapper::get()
->with('l11n')
->where('id', (int) $request->getData('id'))
->where('l11n/language', $response->header->l11n->language)
->execute();
$view->data['l11nView'] = new \Web\Backend\Views\L11nView($this->app->l11nManager, $request, $response);
/** @var \phpOMS\Localization\BaseStringL11n[] $l11nValues */
$l11nValues = PaymentTermL11nMapper::getAll()
->where('ref', $view->data['type']->id)
->execute();
$view->data['l11nValues'] = $l11nValues;
return $view;
}
/**
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return RenderableInterface
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function viewShippingList(RequestAbstract $request, ResponseAbstract $response, array $data = []) : RenderableInterface
{
$view = new View($this->app->l11nManager, $request, $response);
$view->setTemplate('/Modules/Billing/Theme/Backend/shipping-type-list');
$view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1002901101, $request, $response);
$view->data['types'] = ShippingTermMapper::getAll()
->with('l11n')
->where('l11n/language', $response->header->l11n->language)
->execute();
return $view;
}
/**
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return RenderableInterface
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function viewShippingView(RequestAbstract $request, ResponseAbstract $response, array $data = []) : RenderableInterface
{
$view = new View($this->app->l11nManager, $request, $response);
$view->setTemplate('/Modules/Billing/Theme/Backend/shipping-view');
$view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1002901101, $request, $response);
$view->data['type'] = ShippingTermMapper::get()
->with('l11n')
->where('id', (int) $request->getData('id'))
->where('l11n/language', $response->header->l11n->language)
->execute();
$view->data['l11nView'] = new \Web\Backend\Views\L11nView($this->app->l11nManager, $request, $response);
/** @var \phpOMS\Localization\BaseStringL11n[] $l11nValues */
$l11nValues = ShippingTermL11nMapper::getAll()
->where('ref', $view->data['type']->id)
->execute();
$view->data['l11nValues'] = $l11nValues;
return $view;
}

View File

@ -14,8 +14,11 @@ declare(strict_types=1);
namespace Modules\Billing\Controller;
use Modules\Billing\Models\BillElement;
use Modules\Billing\Models\BillElementMapper;
use Modules\Billing\Models\BillMapper;
use Modules\Billing\Models\BillTypeMapper;
use Modules\Billing\Models\InvoiceRecognition;
use Modules\Billing\Models\NullBillType;
use Modules\Billing\Models\SettingsEnum;
use Modules\Payment\Models\PaymentType;
@ -23,7 +26,11 @@ use Modules\SupplierManagement\Models\NullSupplier;
use Modules\SupplierManagement\Models\Supplier;
use Modules\SupplierManagement\Models\SupplierMapper;
use phpOMS\Contract\RenderableInterface;
use phpOMS\Localization\LanguageDetection\Language;
use phpOMS\Localization\ISO4217CharEnum;
use phpOMS\Localization\ISO4217DecimalEnum;
use phpOMS\Localization\Localization;
use phpOMS\Message\Http\HttpRequest;
use phpOMS\Message\Http\HttpResponse;
use phpOMS\Message\RequestAbstract;
use phpOMS\Message\ResponseAbstract;
use phpOMS\Stdlib\Base\FloatInt;
@ -40,7 +47,7 @@ use phpOMS\Views\View;
final class CliController extends Controller
{
/**
* Analyse supplier bill
* Analyze supplier bill
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
@ -53,32 +60,54 @@ final class CliController extends Controller
*/
public function cliParseSupplierBill(RequestAbstract $request, ResponseAbstract $response, array $data = []) : RenderableInterface
{
$view = new View($this->app->l11nManager, $request, $response);
$view->setTemplate('/Modules/Billing/Theme/Cli/bill-parsed');
/** @var \Model\Setting $setting */
$setting = $this->app->appSettings->get(
names: SettingsEnum::ORIGINAL_MEDIA_TYPE,
names: SettingsEnum::EXTERNAL_MEDIA_TYPE,
module: self::NAME
);
$originalType = $request->getDataInt('type') ?? (int) $setting->content;
$externalType = $request->getDataInt('-t') ?? (int) $setting->content;
/** @var \Modules\Billing\Models\Bill $bill */
$bill = BillMapper::get()
->with('media')
->with('media/types')
->with('media/content')
->where('id', (int) $request->getData('i'))
->where('media/types/id', $originalType)
->with('elements')
->with('files')
->with('files/types')
->with('files/content')
->where('id', (int) $request->getData('-i'))
->where('files/types', $externalType)
->execute();
if ($bill->id === 0) {
return $view;
}
$old = clone $bill;
$content = \strtolower($bill->getFileByType($originalType)->content->content ?? '');
$content = \strtolower($bill->getFileByType($externalType)->content->content ?? '');
$lines = \explode("\n", $content);
foreach ($lines as $line => $value) {
if (empty(\trim($value))) {
unset($lines[$line]);
}
}
$lines = \array_values($lines);
$language = InvoiceRecognition::detectLanguage($content);
if (!\in_array($language, ['en', 'de'])) {
$language = 'en';
}
$language = $this->detectLanguage($content);
$bill->language = $language;
$identifierContent = \file_get_contents(__DIR__ . '/../Models/billIdentifier.json');
$l11n = Localization::fromLanguage($language);
$identifierContent = \file_get_contents(__DIR__ . '/../Models/bill_identifier.json');
if ($identifierContent === false) {
$identifierContent = '{}';
}
@ -97,16 +126,37 @@ final class CliController extends Controller
$supplierId = $this->matchSupplier($content, $suppliers);
$bill->supplier = new NullSupplier($supplierId);
$supplier = $suppliers[$supplierId] ?? new NullSupplier();
$supplier = $suppliers[$supplierId] ?? new NullSupplier();
$bill->billTo = $supplier->account->name1;
$bill->billAddress = $supplier->mainAddress->address;
$bill->billCity = $supplier->mainAddress->city;
$bill->billZip = $supplier->mainAddress->postal;
$bill->billCountry = $supplier->mainAddress->getCountry();
if ($supplier->id !== 0) {
$bill->billTo = $supplier->account->name1;
$bill->billAddress = $supplier->mainAddress->address;
$bill->billCity = $supplier->mainAddress->city;
$bill->billZip = $supplier->mainAddress->postal;
$bill->billCountry = $supplier->mainAddress->country;
} else {
$bill->billCountry = InvoiceRecognition::findCountry($lines, $identifiers, $language);
}
$currency = InvoiceRecognition::findCurrency($lines);
$countryCurrency = ISO4217CharEnum::currencyFromCountry($bill->billCountry);
// Identified currency has to be country currency or one of the top globally used currencies
if ($currency !== \in_array($currency, [
$countryCurrency, ISO4217CharEnum::_USD, ISO4217CharEnum::_EUR, ISO4217CharEnum::_JPY,
ISO4217CharEnum::_GBP, ISO4217CharEnum::_AUD, ISO4217CharEnum::_CAD, ISO4217CharEnum::_CHF,
ISO4217CharEnum::_CNH, ISO4217CharEnum::_CNY,
])
) {
$currency = $countryCurrency;
}
$bill->currency = $currency;
$rd = -FloatInt::MAX_DECIMALS + ISO4217DecimalEnum::getByName('_' . $bill->currency);
/* Type */
$type = $this->findSupplierInvoiceType($content, $identifiers['type'], $language);
$type = InvoiceRecognition::findSupplierInvoiceType($content, $identifiers['type'], $language);
/** @var \Modules\Billing\Models\BillType $billType */
$billType = BillTypeMapper::get()
@ -116,233 +166,289 @@ final class CliController extends Controller
$bill->type = new NullBillType($billType->id);
/* Number */
$billNumber = $this->findBillNumber($lines, $identifiers['bill_no'][$language]);
$bill->number = $billNumber;
$billNumber = InvoiceRecognition::findBillNumber($lines, $identifiers['bill_no'][$language]);
$bill->external = $billNumber;
/* Reference / PO */
// @todo implement
/* Date */
$billDateTemp = $this->findBillDate($lines, $identifiers['bill_date'][$language]);
$billDate = $this->parseDate($billDateTemp, $supplier, $identifiers['date_format']);
$billDateTemp = InvoiceRecognition::findBillDate($lines, $identifiers['bill_date'][$language]);
$billDate = InvoiceRecognition::parseDate($billDateTemp, $identifiers['date_format'], $supplier->getAttribute('bill_date_format')->value->valueStr ?? '');
$bill->billDate = $billDate;
/* Due */
$billDueTemp = $this->findBillDue($lines, $identifiers['bill_date'][$language]);
$billDue = $this->parseDate($billDueTemp, $supplier, $identifiers['date_format']);
// @todo: implement multiple due dates for bills
$billDueTemp = InvoiceRecognition::findBillDue($lines, $identifiers['bill_due'][$language]);
$billDue = InvoiceRecognition::parseDate($billDueTemp, $identifiers['date_format'], $supplier->getAttribute('bill_date_format')->value->valueStr ?? '');
// @todo implement multiple due dates for bills
/* Total Gross */
$totalGross = $this->findBillGross($lines, $identifiers['total_gross'][$language]);
$bill->grossCosts = new FloatInt($totalGross);
/* Total */
$totalGross = InvoiceRecognition::findBillGross($lines, $identifiers['total_gross'][$language]);
$totalNet = InvoiceRecognition::findBillNet($lines, $identifiers['total_net'][$language]);
// The number format needs to be corrected:
// Languages don't always respect the l11n number format
// Sometimes parsing errors can happen
$format = FloatInt::identifyNumericFormat($totalGross);
if ($format !== null) {
$l11n->thousands = $format['thousands'];
$l11n->decimal = $format['decimal'];
}
$bill->grossSales = new FloatInt($totalGross, $l11n->thousands, $l11n->decimal);
$bill->netSales = new FloatInt($totalNet, $l11n->thousands, $l11n->decimal);
/* Total Tax */
// @todo taxes depend on local tax id (if company in Germany but invoice from US -> only gross amount important, there is no net)
$totalTaxAmount = InvoiceRecognition::findBillTaxAmount($lines, $identifiers['total_tax'][$language]);
$taxRates = InvoiceRecognition::findBillTaxRates($lines, $identifiers['tax_rate'][$language]);
if ($bill->netSales->value === 0) {
$bill->netSales->value = $taxRates === 0
? $bill->grossSales->value
: (int) \round($bill->grossSales->value / (1.0 + $taxRates / (FloatInt::DIVISOR * 100)), $rd);
}
if ($bill->grossSales->value === 0) {
$bill->grossSales->value = $taxRates === 0
? $bill->netSales->value
: $bill->netSales->value + ((int) \round($bill->netSales->value * $taxRates / (FloatInt::DIVISOR * 100), $rd));
}
// We just assume that finding the net sales value is more likely
// If this turns out to be false, we need to recalculate the netSales from the grossSales instead
if ($bill->grossSales->value === $bill->netSales->value) {
$bill->grossSales->value = $bill->netSales->value + ((int) \round($bill->netSales->value * $taxRates / (FloatInt::DIVISOR * 100), $rd));
}
if ($taxRates === 0 && $bill->netSales->value !== $bill->grossSales->value) {
$taxRates = ((int) ($bill->grossSales->value / ($bill->grossSales->value / FloatInt::DIVISOR))) - FloatInt::DIVISOR;
}
/* Item lines */
$itemLines = InvoiceRecognition::findBillItemLines($lines, $identifiers['item_table'][$language]);
// @todo Try to find item from item database
// @todo Some of the element value setting is unnecessary as it happens also in the recalculatePrices()
// Same goes for the bill element creations further down below
if (empty($bill->elements)) {
$itemLineEnd = 0;
foreach ($itemLines as $line => $itemLine) {
$itemLineEnd = $line;
$billElement = new BillElement();
$billElement->bill = $bill;
$billElement->taxR->value = $taxRates;
if (isset($itemLine['description'])) {
$billElement->itemName = \trim($itemLine['description']);
}
if (isset($itemLine['quantity'])) {
$billElement->quantity = new FloatInt($itemLine['quantity'], $l11n->thousands, $l11n->decimal);
}
// Unit
if (isset($itemLine['price'])) {
$billElement->singleListPriceNet = new FloatInt($itemLine['price'], $l11n->thousands, $l11n->decimal);
$billElement->singleSalesPriceNet = $billElement->singleListPriceNet;
$billElement->singlePurchasePriceNet = $billElement->singleSalesPriceNet;
if ($billElement->taxR->value > 0) {
$billElement->singleListPriceGross->value = $billElement->singleListPriceNet->value + ((int) \round($billElement->singleSalesPriceNet->value * $billElement->taxR->value / (FloatInt::DIVISOR * 100), $rd));
$billElement->singleSalesPriceGross = $billElement->singleListPriceGross;
} else {
$billElement->singleListPriceGross = $billElement->singleListPriceNet;
$billElement->singleSalesPriceGross = $billElement->singleListPriceGross;
}
}
// Total
if (isset($itemLine['total'])) {
$billElement->totalListPriceNet = new FloatInt($itemLine['total'], $l11n->thousands, $l11n->decimal);
$billElement->totalSalesPriceNet = $billElement->totalListPriceNet;
$billElement->totalPurchasePriceNet = $billElement->totalSalesPriceNet;
if ($billElement->taxR->value > 0) {
$billElement->totalListPriceGross->value = $billElement->totalListPriceNet->value + ((int) \round($billElement->totalSalesPriceNet->value * $billElement->taxR->value / (FloatInt::DIVISOR * 100), $rd));
$billElement->totalSalesPriceGross = $billElement->totalListPriceGross;
} else {
$billElement->totalListPriceGross = $billElement->totalListPriceNet;
$billElement->totalSalesPriceGross = $billElement->totalListPriceGross;
}
}
$billElement->taxP->value = $billElement->totalSalesPriceGross->value - $billElement->totalSalesPriceNet->value;
$billElement->recalculatePrices();
$bill->elements[] = $billElement;
$this->createModel($request->header->account, $billElement, BillElementMapper::class, 'bill_element', $request->getOrigin());
}
/* Total Special */
// @question How do we want to apply total discounts?
// Option 1: Apply in relation to the amount per line item (this would be correct for stock evaluation)
// Option 2: Additional element (For correct stock evaluation we could do a internal/backend correction in the lot price calculation)
//
// Option 2 seems nicer from a user perspective!
$totalSpecial = InvoiceRecognition::findBillSpecial($lines, $identifiers, $language, $itemLineEnd);
foreach ($totalSpecial as $key => $amount) {
if ($amount === 0) {
continue;
}
$key = \str_replace('total_', '', $key);
$billElement = new BillElement();
$billElement->bill = $bill;
$billElement->taxR->value = $taxRates;
$internalRequest = new HttpRequest();
$internalResponse = new HttpResponse();
$internalRequest->header->account = $request->header->account;
$internalRequest->header->l11n = $request->header->l11n;
$internalRequest->setData('search', $key);
$internalRequest->setData('limit', 1);
$internalResponse->header->l11n = clone $response->header->l11n;
$internalResponse->header->l11n->language = $bill->language;
$this->app->moduleManager->get('ItemManagement', 'Api')->apiItemFind($internalRequest, $internalResponse);
$item = $internalResponse->getDataArray('')[0];
$billElement->itemName = $key;
if ($item->id !== 0) {
$billElement->item = $item;
$billElement->itemNumber = $item->number;
$billElement->itemName = $item->getL11n('name1')->content;
}
$billElement->quantity->value = FloatInt::DIVISOR;
// Unit
$billElement->singleListPriceNet = new FloatInt($amount, $l11n->thousands, $l11n->decimal);
$billElement->singleSalesPriceNet = $billElement->singleListPriceNet;
$billElement->singlePurchasePriceNet = $billElement->singleSalesPriceNet;
if ($billElement->taxR->value > 0) {
$billElement->singleListPriceGross->value = $billElement->singleListPriceNet->value + ((int) \round($billElement->singleSalesPriceNet->value * $billElement->taxR->value / (FloatInt::DIVISOR * 100), $rd));
$billElement->singleSalesPriceGross = $billElement->singleListPriceGross;
} else {
$billElement->singleListPriceGross = $billElement->singleListPriceNet;
$billElement->singleSalesPriceGross = $billElement->singleListPriceGross;
}
// Total
$billElement->totalListPriceNet = $billElement->singleListPriceNet;
$billElement->totalSalesPriceNet = $billElement->singleSalesPriceNet;
$billElement->totalPurchasePriceNet = $billElement->singlePurchasePriceNet;
$billElement->totalListPriceGross = $billElement->singleListPriceGross;
$billElement->totalSalesPriceGross = $billElement->singleSalesPriceGross;
$billElement->taxP->value = $billElement->totalSalesPriceGross->value - $billElement->totalSalesPriceNet->value;
$billElement->recalculatePrices();
$bill->elements[] = $billElement;
$this->createModel($request->header->account, $billElement, BillElementMapper::class, 'bill_element', $request->getOrigin());
}
}
if (!empty($bill->elements)) {
// Calculate totals from elements
$totalNet = 0;
$totalGross = 0;
foreach ($bill->elements as $element) {
$totalNet += $element->totalSalesPriceNet->value;
$totalGross += $element->totalSalesPriceGross->value;
}
$bill->grossSales = new FloatInt($totalGross);
$bill->netCosts = new FloatInt($totalNet);
$bill->netSales = $bill->netCosts;
}
$bill->taxP->value = $bill->grossSales->value - $bill->netSales->value;
// No elements could be identified -> make total a bill element
if (empty($itemLines) && empty($bill->elements)) {
$billElement = new BillElement();
$billElement->bill = $bill;
// List price
$billElement->singleListPriceNet->value = $bill->netSales->value;
$billElement->totalListPriceNet->value = $bill->netSales->value;
$billElement->singleListPriceGross->value = $bill->grossSales->value;
$billElement->totalListPriceGross->value = $bill->grossSales->value;
// Unit price
$billElement->singleSalesPriceNet->value = $bill->netSales->value;
$billElement->singlePurchasePriceNet->value = $bill->netSales->value;
$billElement->singleSalesPriceGross->value = $bill->grossSales->value;
// Total
$billElement->totalSalesPriceNet->value = $bill->netSales->value;
$billElement->totalPurchasePriceNet->value = $bill->netSales->value;
$billElement->totalSalesPriceGross->value = $bill->grossSales->value;
$billElement->taxP->value = $bill->taxP->value;
$billElement->taxR->value = $taxRates;
$billElement->recalculatePrices();
$bill->elements[] = $billElement;
$this->createModel($request->header->account, $billElement, BillElementMapper::class, 'bill_element', $request->getOrigin());
}
// Re-calculate totals from elements due to change
$totalNet = 0;
$totalGross = 0;
foreach ($bill->elements as $element) {
$totalNet += $element->totalSalesPriceNet->value;
$totalGross += $element->totalSalesPriceGross->value;
}
$bill->grossSales = new FloatInt($totalGross);
$bill->netCosts = new FloatInt($totalNet);
$bill->netSales = $bill->netCosts;
$bill->taxP->value = $bill->grossSales->value - $bill->netSales->value;
$this->updateModel($request->header->account, $old, $bill, BillMapper::class, 'bill_parsing', $request->getOrigin());
$view = new View($this->app->l11nManager, $request, $response);
$view->setTemplate('/Modules/Billing/Theme/Cli/bill-parsed');
// @todo change tax code during/after bill parsing
$view->data['bill'] = $bill;
// Fix internal document
$request->setData('bill', $bill->id, true);
$billResponse = new HttpResponse();
$this->app->moduleManager->get('Billing', 'ApiBill')->apiBillPdfArchiveCreate($request, $billResponse);
return $view;
}
/**
* Detect language from content
*
* @param string $content String to analyze
*
* @return string
*
* @since 1.0.0
*/
private function detectLanguage(string $content) : string
{
$detector = new Language();
$language = $detector->detect($content)->bestResults()->close();
if (!\is_array($language) || \count($language) < 1) {
return 'en';
}
return \substr(\array_keys($language)[0], 0, 2);
}
/**
* Detect the supplier bill type
*
* @param string $content String to analyze
* @param array $types Possible bill types
* @param string $language Bill language
*
* @return string
*
* @since 1.0.0
*/
private function findSupplierInvoiceType(string $content, array $types, string $language) : string
{
$bestPos = \strlen($content);
$bestMatch = '';
foreach ($types as $name => $type) {
foreach ($type[$language] as $l11n) {
$found = \stripos($content, \strtolower($l11n));
if ($found !== false && $found < $bestPos) {
$bestPos = $found;
$bestMatch = $name;
}
}
}
return empty($bestMatch) ? 'purchase_invoice' : $bestMatch;
}
/**
* Detect the supplier bill number
*
* @param string[] $lines Bill lines
* @param array $matches Number match patterns
*
* @return string
*
* @since 1.0.0
*/
private function findBillNumber(array $lines, array $matches) : string
{
$bestPos = \count($lines);
$bestMatch = '';
$found = [];
foreach ($matches as $match) {
foreach ($lines as $row => $line) {
if (\preg_match($match, $line, $found) === 1) {
if ($row < $bestPos) {
$bestPos = $row;
$bestMatch = \trim($found['bill_no']);
}
break;
}
}
}
return $bestMatch;
}
/**
* Detect the supplier bill due date
*
* @param string[] $lines Bill lines
* @param array $matches Due match patterns
*
* @return string
*
* @since 1.0.0
*/
private function findBillDue(array $lines, array $matches) : string
{
$bestPos = \count($lines);
$bestMatch = '';
$found = [];
foreach ($matches as $match) {
foreach ($lines as $row => $line) {
if (\preg_match($match, $line, $found) === 1) {
if ($row < $bestPos) {
// @todo: don't many invoices have the due date at the bottom? bestPos doesn't make sense?!
$bestPos = $row;
$bestMatch = \trim($found['bill_due']);
}
break;
}
}
}
return $bestMatch;
}
/**
* Detect the supplier bill date
*
* @param string[] $lines Bill lines
* @param array $matches Date match patterns
*
* @return string
*
* @since 1.0.0
*/
private function findBillDate(array $lines, array $matches) : string
{
$bestPos = \count($lines);
$bestMatch = '';
$found = [];
foreach ($matches as $match) {
foreach ($lines as $row => $line) {
if (\preg_match($match, $line, $found) === 1) {
if ($row < $bestPos) {
$bestPos = $row;
$bestMatch = \trim($found['bill_date']);
}
break;
}
}
}
return $bestMatch;
}
/**
* Detect the supplier bill gross amount
*
* @param string[] $lines Bill lines
* @param array $matches Gross match patterns
*
* @return int
*
* @since 1.0.0
*/
private function findBillGross(array $lines, array $matches) : int
{
$bestMatch = 0;
$found = [];
foreach ($matches as $match) {
foreach ($lines as $line) {
if (\preg_match($match, $line, $found) === 1) {
$temp = \trim($found['total_gross']);
$posD = \stripos($temp, '.');
$posK = \stripos($temp, ',');
$hasDecimal = ($posD !== false || $posK !== false)
&& \max((int) $posD, (int) $posK) + 3 >= \strlen($temp);
$gross = ((int) \str_replace(['.', ','], ['', ''], $temp)) * ($hasDecimal
? 100
: 10000);
if ($gross > $bestMatch) {
$bestMatch = $gross;
}
}
}
}
return $bestMatch;
}
/**
* Find possible supplier id
*
* Priorities:
* 1. bill_match_pattern
* 2. name1 + iban
* 2. name1 + IBAN
* 3. name1 + city || address
* 4. name1
*
* @param string $content Content to analyze
* @param Supplier[] $suppliers Suppliers
@ -355,7 +461,7 @@ final class CliController extends Controller
{
// bill_match_pattern
foreach ($suppliers as $supplier) {
// @todo: consider to support regex?
// @todo consider to support regex?
if ((!empty($supplier->getAttribute('bill_match_pattern')->value->valueStr)
&& \stripos($content, $supplier->getAttribute('bill_match_pattern')->value->valueStr) !== false)
) {
@ -363,7 +469,7 @@ final class CliController extends Controller
}
}
// name1 + iban
// name1 + IBAN
foreach ($suppliers as $supplier) {
if (\stripos($content, $supplier->account->name1) !== false) {
$ibans = $supplier->getPaymentsByType(PaymentType::SWIFT);
@ -388,44 +494,6 @@ final class CliController extends Controller
}
}
// name1
foreach ($suppliers as $supplier) {
if (\stripos($content, $supplier->account->name1) !== false) {
return $supplier->id;
}
}
return 0;
}
/**
* Create DateTime from date string
*
* @param string $date Date string
* @param Supplier $supplier Supplier
* @param string[] $formats Date formats
*
* @return null|\DateTime
*
* @since 1.0.0
*/
private function parseDate(string $date, Supplier $supplier, array $formats) : ?\DateTime
{
if ((!empty($supplier->getAttribute('bill_date_format')->value->valueStr))) {
$dt = \DateTime::createFromFormat(
$supplier->getAttribute('bill_date_format')->value->valueStr ?? '',
$date
);
return $dt === false ? new \DateTime('1970-01-01') : $dt;
}
foreach ($formats as $format) {
if (($obj = \DateTime::createFromFormat($format, $date)) !== false) {
return $obj === false ? null : $obj;
}
}
return null;
}
}

View File

@ -1,6 +1,6 @@
# Individual Contributor License Agreement ("CLA") 1.0
Thank you for your interest in Karaka-Management (the "Company"). In order to clarify the intellectual property license granted with Contributions from any person or entity, the Company must provide a Contributor License Agreement ("CLA") on file that has been made available to each Contributor. This license is for your protection as a Contributor as well as the protection of the Company and its users; it does not change your rights to use your own Contributions for any other purpose.
Thank you for your interest in Jingga e. K. (the "Company"). In order to clarify the intellectual property license granted with Contributions from any person or entity, the Company must provide a Contributor License Agreement ("CLA") on file that has been made available to each Contributor. This license is for your protection as a Contributor as well as the protection of the Company and its users; it does not change your rights to use your own Contributions for any other purpose.
By contributing to the Company You accept and agree to the following terms and conditions for Your present and future Contributions submitted to the Company. In return, the Company shall not use Your Contributions in a way that is contrary to the public benefit or inconsistent with its bylaws in effect at the time of the Contribution. Except for the license granted herein to the Company and recipients of software distributed by the Company, You reserve all right, title, and interest in and to Your Contributions.

View File

@ -42,6 +42,8 @@ final class BillAttributeTypeMapper extends DataMapperFactory
'billing_attr_type_datatype' => ['name' => 'billing_attr_type_datatype', 'type' => 'int', 'internal' => 'datatype'],
'billing_attr_type_fields' => ['name' => 'billing_attr_type_fields', 'type' => 'int', 'internal' => 'fields'],
'billing_attr_type_custom' => ['name' => 'billing_attr_type_custom', 'type' => 'bool', 'internal' => 'custom'],
'billing_attr_type_repeatable' => ['name' => 'billing_attr_type_repeatable', 'type' => 'bool', 'internal' => 'repeatable'],
'billing_attr_type_internal' => ['name' => 'billing_attr_type_internal', 'type' => 'bool', 'internal' => 'isInternal'],
'billing_attr_type_pattern' => ['name' => 'billing_attr_type_pattern', 'type' => 'string', 'internal' => 'validationPattern'],
'billing_attr_type_required' => ['name' => 'billing_attr_type_required', 'type' => 'bool', 'internal' => 'isRequired'],
];

View File

@ -37,10 +37,10 @@ final class BillAttributeValueL11nMapper extends DataMapperFactory
* @since 1.0.0
*/
public const COLUMNS = [
'billing_attr_value_l11n_id' => ['name' => 'billing_attr_value_l11n_id', 'type' => 'int', 'internal' => 'id'],
'billing_attr_value_l11n_title' => ['name' => 'billing_attr_value_l11n_title', 'type' => 'string', 'internal' => 'content', 'autocomplete' => true],
'billing_attr_value_l11n_value' => ['name' => 'billing_attr_value_l11n_value', 'type' => 'int', 'internal' => 'ref'],
'billing_attr_value_l11n_lang' => ['name' => 'billing_attr_value_l11n_lang', 'type' => 'string', 'internal' => 'language'],
'billing_attr_value_l11n_id' => ['name' => 'billing_attr_value_l11n_id', 'type' => 'int', 'internal' => 'id'],
'billing_attr_value_l11n_title' => ['name' => 'billing_attr_value_l11n_title', 'type' => 'string', 'internal' => 'content', 'autocomplete' => true],
'billing_attr_value_l11n_value' => ['name' => 'billing_attr_value_l11n_value', 'type' => 'int', 'internal' => 'ref'],
'billing_attr_value_l11n_lang' => ['name' => 'billing_attr_value_l11n_lang', 'type' => 'string', 'internal' => 'language'],
];
/**

View File

@ -37,15 +37,15 @@ final class BillAttributeValueMapper extends DataMapperFactory
* @since 1.0.0
*/
public const COLUMNS = [
'billing_attr_value_id' => ['name' => 'billing_attr_value_id', 'type' => 'int', 'internal' => 'id'],
'billing_attr_value_default' => ['name' => 'billing_attr_value_default', 'type' => 'bool', 'internal' => 'isDefault'],
'billing_attr_value_valueStr' => ['name' => 'billing_attr_value_valueStr', 'type' => 'string', 'internal' => 'valueStr'],
'billing_attr_value_valueInt' => ['name' => 'billing_attr_value_valueInt', 'type' => 'int', 'internal' => 'valueInt'],
'billing_attr_value_valueDec' => ['name' => 'billing_attr_value_valueDec', 'type' => 'float', 'internal' => 'valueDec'],
'billing_attr_value_valueDat' => ['name' => 'billing_attr_value_valueDat', 'type' => 'DateTime', 'internal' => 'valueDat'],
'billing_attr_value_unit' => ['name' => 'billing_attr_value_unit', 'type' => 'string', 'internal' => 'unit'],
'billing_attr_value_deptype' => ['name' => 'billing_attr_value_deptype', 'type' => 'int', 'internal' => 'dependingAttributeType'],
'billing_attr_value_depvalue' => ['name' => 'billing_attr_value_depvalue', 'type' => 'int', 'internal' => 'dependingAttributeValue'],
'billing_attr_value_id' => ['name' => 'billing_attr_value_id', 'type' => 'int', 'internal' => 'id'],
'billing_attr_value_default' => ['name' => 'billing_attr_value_default', 'type' => 'bool', 'internal' => 'isDefault'],
'billing_attr_value_valueStr' => ['name' => 'billing_attr_value_valueStr', 'type' => 'string', 'internal' => 'valueStr'],
'billing_attr_value_valueInt' => ['name' => 'billing_attr_value_valueInt', 'type' => 'int', 'internal' => 'valueInt'],
'billing_attr_value_valueDec' => ['name' => 'billing_attr_value_valueDec', 'type' => 'float', 'internal' => 'valueDec'],
'billing_attr_value_valueDat' => ['name' => 'billing_attr_value_valueDat', 'type' => 'DateTime', 'internal' => 'valueDat'],
'billing_attr_value_unit' => ['name' => 'billing_attr_value_unit', 'type' => 'string', 'internal' => 'unit'],
'billing_attr_value_deptype' => ['name' => 'billing_attr_value_deptype', 'type' => 'int', 'internal' => 'dependingAttributeType'],
'billing_attr_value_depvalue' => ['name' => 'billing_attr_value_depvalue', 'type' => 'int', 'internal' => 'dependingAttributeValue'],
];
/**
@ -59,6 +59,7 @@ final class BillAttributeValueMapper extends DataMapperFactory
'mapper' => BillAttributeValueL11nMapper::class,
'table' => 'billing_attr_value_l11n',
'self' => 'billing_attr_value_l11n_value',
'column' => 'content',
'external' => null,
],
];

View File

@ -17,7 +17,6 @@ namespace Modules\Billing\Models;
use Modules\Admin\Models\Account;
use Modules\Admin\Models\NullAccount;
use Modules\ClientManagement\Models\Client;
use Modules\Media\Models\Collection;
use Modules\SupplierManagement\Models\Supplier;
use phpOMS\Localization\ISO4217CharEnum;
use phpOMS\Localization\ISO639x1Enum;
@ -66,6 +65,8 @@ class Bill implements \JsonSerializable
*/
public string $number = '';
public string $external = '';
/**
* Bill type.
*
@ -74,7 +75,9 @@ class Bill implements \JsonSerializable
*/
public BillType $type;
public ?Collection $template = null;
public bool $isTemplate = false;
public bool $isArchived = false;
/**
* Bill status.
@ -239,15 +242,13 @@ class Bill implements \JsonSerializable
public string $billEmail = '';
/**
* Person refering for this order.
* Person referring for this order.
*
* @var Account
* @since 1.0.0
*/
public Account $referral;
public string $referralName = '';
/**
* Net amount.
*
@ -256,14 +257,6 @@ class Bill implements \JsonSerializable
*/
public FloatInt $netProfit;
/**
* Gross amount.
*
* @var FloatInt
* @since 1.0.0
*/
public FloatInt $grossProfit;
/**
* Costs in net.
*
@ -272,14 +265,6 @@ class Bill implements \JsonSerializable
*/
public FloatInt $netCosts;
/**
* Profit in net.
*
* @var FloatInt
* @since 1.0.0
*/
public FloatInt $grossCosts;
/**
* Costs in net.
*
@ -305,28 +290,14 @@ class Bill implements \JsonSerializable
public FloatInt $netDiscount;
/**
* Profit in net.
* Tax amount
*
* @var FloatInt
* @since 1.0.0
*/
public FloatInt $grossDiscount;
public FloatInt $taxP;
/**
* Insurance fees in net.
*
* @var FloatInt
* @since 1.0.0
*/
public FloatInt $insurance;
/**
* Freight in net.
*
* @var FloatInt
* @since 1.0.0
*/
public FloatInt $freight;
public ?int $accTaxCode = null;
/**
* Currency.
@ -360,12 +331,6 @@ class Bill implements \JsonSerializable
*/
public string $info = '';
/**
* Payment type.
*
* @var int
* @since 1.0.0
*/
public int $payment = 0;
/**
@ -384,6 +349,10 @@ class Bill implements \JsonSerializable
*/
public int $terms = 0;
public ?int $paymentTerms = null;
public ?int $shippingTerms = null;
/**
* Terms text.
*
@ -392,14 +361,6 @@ class Bill implements \JsonSerializable
*/
public string $termsText = '';
/**
* Shipping.
*
* @var int
* @since 1.0.0
*/
public int $shipping = 0;
/**
* Shipping text.
*
@ -440,6 +401,18 @@ class Bill implements \JsonSerializable
*/
public int $reference = 0;
public ?int $accSegment = null;
public ?int $accSection = null;
public ?int $accGroup = null;
public ?int $accType = null;
public ?string $fiAccount = null;
// @todo Implement reason for bill (especially useful for credit notes, warehouse bookings)
/**
* Constructor.
*
@ -447,14 +420,12 @@ class Bill implements \JsonSerializable
*/
public function __construct()
{
$this->netProfit = new FloatInt(0);
$this->grossProfit = new FloatInt(0);
$this->netCosts = new FloatInt(0);
$this->grossCosts = new FloatInt(0);
$this->netSales = new FloatInt(0);
$this->grossSales = new FloatInt(0);
$this->netDiscount = new FloatInt(0);
$this->grossDiscount = new FloatInt(0);
$this->netProfit = new FloatInt(0);
$this->netCosts = new FloatInt(0);
$this->netSales = new FloatInt(0);
$this->grossSales = new FloatInt(0);
$this->netDiscount = new FloatInt(0);
$this->taxP = new FloatInt(0);
$this->billDate = new \DateTime('now');
$this->createdAt = new \DateTimeImmutable();
@ -463,18 +434,6 @@ class Bill implements \JsonSerializable
$this->type = new NullBillType();
}
/**
* Get id.
*
* @return int Model id
*
* @since 1.0.0
*/
public function getId() : int
{
return $this->id;
}
/**
* Build the invoice number.
*
@ -492,6 +451,9 @@ class Bill implements \JsonSerializable
'{id}',
'{sequence}',
'{type}',
'{unit}',
'{account}',
'{country}',
],
[
$this->createdAt->format('Y'),
@ -500,6 +462,9 @@ class Bill implements \JsonSerializable
$this->id,
$this->sequence,
$this->type->id,
$this->unit,
$this->accountNumber,
$this->billCountry,
],
$this->type->numberFormat
);
@ -521,32 +486,6 @@ class Bill implements \JsonSerializable
return $this->number;
}
/**
* Get status
*
* @return int
*
* @since 1.0.0
*/
public function getStatus() : int
{
return $this->status;
}
/**
* Set status
*
* @param int $status Status
*
* @return void
*
* @since 1.0.0
*/
public function setStatus(int $status) : void
{
$this->status = $status;
}
/**
* Get paymentStatus
*
@ -573,96 +512,6 @@ class Bill implements \JsonSerializable
$this->paymentStatus = $paymentStatus;
}
/**
* Set currency.
*
* @param string $currency Currency
*
* @return void
*
* @since 1.0.0
*/
public function setCurrency(string $currency) : void
{
$this->currency = $currency;
}
/**
* Get currency.
*
* @return string
*
* @since 1.0.0
*/
public function getCurrency() : string
{
return $this->currency;
}
/**
* Get vouchers.
*
* @return array
*
* @since 1.0.0
*/
public function getVouchers() : array
{
return $this->vouchers;
}
/**
* Add voucher.
*
* @param string $voucher Voucher code
*
* @return void
*
* @since 1.0.0
*/
public function addVoucher(string $voucher) : void
{
$this->vouchers[] = $voucher;
}
/**
* Get tracking ids for shipment.
*
* @return array
*
* @since 1.0.0
*/
public function getTrackings() : array
{
return $this->trackings;
}
/**
* Add tracking id.
*
* @param string $tracking Tracking id
*
* @return void
*
* @since 1.0.0
*/
public function addTracking(string $tracking) : void
{
$this->trackings[] = $tracking;
}
/**
* Get Bill elements.
*
* @return BillElement[]
*
* @since 1.0.0
*/
public function getElements() : array
{
return $this->elements;
}
/**
* Add Bill element.
*
@ -676,16 +525,157 @@ class Bill implements \JsonSerializable
{
$this->elements[] = $element;
$this->netProfit->add($element->totalProfitNet->getInt());
$this->grossProfit->add($element->totalProfitGross->getInt());
$this->netCosts->add($element->totalPurchasePriceNet->getInt());
$this->grossCosts->add($element->totalPurchasePriceGross->getInt());
$this->netSales->add($element->totalSalesPriceNet->getInt());
$this->grossSales->add($element->totalSalesPriceGross->getInt());
$this->netDiscount->add($element->totalDiscountP->getInt());
$this->netProfit->value += $element->totalProfitNet->value;
$this->netCosts->value += $element->totalPurchasePriceNet->value;
$this->netSales->value += $element->totalSalesPriceNet->value;
$this->grossSales->value += $element->totalSalesPriceGross->value;
$this->netDiscount->value += $element->totalDiscountP->value;
}
// @todo: Discount might be in quantities
$this->grossDiscount->add((int) ($element->taxR->getInt() * $element->totalDiscountP->getInt() / 10000));
/**
* Validate the correctness of the bill
*
* @return bool
*
* @todo also consider rounding similarly to recalculatePrices in elements
*
* @since 1.0.0
*/
public function isValid() : bool
{
return $this->validateTaxAmountElements()
&& $this->validateProfit()
&& $this->validateGrossElements()
&& $this->validatePriceQuantityElements()
&& $this->validateNetElements()
&& $this->validateNetGross()
&& $this->areElementsValid();
}
/**
* Validate the correctness of the bill elements
*
* @return bool
*
* @since 1.0.0
*/
public function areElementsValid() : bool
{
foreach ($this->elements as $element) {
if (!$element->isValid()) {
return false;
}
}
return true;
}
/**
* Validate the correctness of the net and gross values
*
* @return bool
*
* @since 1.0.0
*/
public function validateNetGross() : bool
{
return $this->netSales->value <= $this->grossSales->value;
}
/**
* Validate the correctness of the profit
*
* @return bool
*
* @since 1.0.0
*/
public function validateProfit() : bool
{
return $this->netSales->value - $this->netCosts->value === $this->netProfit->value;
}
/**
* Validate the correctness of the taxes
*
* @return bool
*
* @since 1.0.0
*/
public function validateTax() : bool
{
return \abs($this->netSales->value + $this->taxP->value - $this->grossSales->value) === 0;
}
/**
* Validate the correctness of the taxes for the elements
*
* @return bool
*
* @since 1.0.0
*/
public function validateTaxAmountElements() : bool
{
$taxes = 0;
foreach ($this->elements as $element) {
$taxes += $element->taxP->value;
}
return $taxes === $this->taxP->value;
}
/**
* Validate the correctness of the net of the elements
*
* @return bool
*
* @since 1.0.0
*/
public function validateNetElements() : bool
{
$net = 0;
foreach ($this->elements as $element) {
$net += $element->totalSalesPriceNet->value;
}
return $net === $this->netSales->value;
}
/**
* Validate the correctness of the gross of the elements
*
* @return bool
*
* @since 1.0.0
*/
public function validateGrossElements()
{
$gross = 0;
foreach ($this->elements as $element) {
$gross += $element->totalSalesPriceGross->value;
}
return $gross === $this->grossSales->value;
}
/**
* Validate the correctness of the quantities and total price
*
* @return bool
*
* @since 1.0.0
*/
public function validatePriceQuantityElements()
{
foreach ($this->elements as $element) {
if ($element->discountQ->value === 0
&& $element->totalDiscountP->value === 0
&& ($element->quantity->value / FloatInt::DIVISOR) * $element->singleSalesPriceNet->value - $element->totalSalesPriceNet->value > 1.0
) {
return false;
}
}
return true;
}
/**
@ -694,21 +684,22 @@ class Bill implements \JsonSerializable
public function toArray() : array
{
return [
'id' => $this->id,
'number' => $this->number,
'type' => $this->type,
'shipTo' => $this->shipTo,
'shipFAO' => $this->shipFAO,
'shipAddress' => $this->shipAddress,
'shipCity' => $this->shipCity,
'shipZip' => $this->shipZip,
'shipCountry' => $this->shipCountry,
'billTo' => $this->billTo,
'billFAO' => $this->billFAO,
'billAddress' => $this->billAddress,
'billCity' => $this->billCity,
'billZip' => $this->billZip,
'billCountry' => $this->billCountry,
'id' => $this->id,
'number' => $this->number,
'external' => $this->external,
'type' => $this->type,
'shipTo' => $this->shipTo,
'shipFAO' => $this->shipFAO,
'shipAddress' => $this->shipAddress,
'shipCity' => $this->shipCity,
'shipZip' => $this->shipZip,
'shipCountry' => $this->shipCountry,
'billTo' => $this->billTo,
'billFAO' => $this->billFAO,
'billAddress' => $this->billAddress,
'billCity' => $this->billCity,
'billZip' => $this->billZip,
'billCountry' => $this->billCountry,
];
}

View File

@ -14,8 +14,12 @@ declare(strict_types=1);
namespace Modules\Billing\Models;
use Modules\Billing\Models\Tax\TaxCombination;
use Modules\Finance\Models\TaxCode;
use Modules\ItemManagement\Models\Container;
use Modules\ItemManagement\Models\Item;
use Modules\ItemManagement\Models\NullItem;
use phpOMS\Localization\ISO4217DecimalEnum;
use phpOMS\Stdlib\Base\FloatInt;
use phpOMS\Stdlib\Base\SmartDateTime;
@ -39,8 +43,9 @@ class BillElement implements \JsonSerializable
public int $order = 0;
/** @todo: consider to reference the model instead of the int, this would make it much easier in other places like the shop */
public ?int $item = null;
public ?Item $item = null;
public ?Container $container = null;
public string $itemNumber = '';
@ -48,12 +53,30 @@ class BillElement implements \JsonSerializable
public string $itemDescription = '';
public int $quantity = 0;
/**
* Line quantity
*
* Careful this also includes the bonus items defined in $discountQ!
*
* @var FloatInt
* @since 1.0.0
*/
public FloatInt $quantity;
public ?Subscription $subscription = null;
/**
* Single unit price
*
* Careful this is NOT corrected by bonus items defined in $discountQ
*
* @var FloatInt
* @since 1.0.0
*/
public FloatInt $singleSalesPriceNet;
public FloatInt $effectiveSingleSalesPriceNet;
public FloatInt $singleSalesPriceGross;
public FloatInt $totalSalesPriceNet;
@ -64,9 +87,9 @@ class BillElement implements \JsonSerializable
public FloatInt $totalDiscountP;
public ?FloatInt $singleDiscountR = null;
public FloatInt $singleDiscountR;
public ?FloatInt $discountQ = null;
public FloatInt $discountQ;
public FloatInt $singleListPriceNet;
@ -78,19 +101,29 @@ class BillElement implements \JsonSerializable
public FloatInt $singlePurchasePriceNet;
public FloatInt $singlePurchasePriceGross;
public FloatInt $totalPurchasePriceNet;
public FloatInt $totalPurchasePriceGross;
public FloatInt $singleProfitNet;
public FloatInt $singleProfitGross;
public FloatInt $totalProfitNet;
public FloatInt $totalProfitGross;
public ?int $itemSegment = null;
public ?int $itemSection = null;
public ?int $itemSalesGroup = null;
public ?int $itemProductGroup = null;
public ?int $itemType = null;
public string $fiAccount = '';
public ?string $costcenter = null;
public ?string $costobject = null;
public ?TaxCombination $taxCombination = null;
/**
* Tax amount
@ -128,6 +161,9 @@ class BillElement implements \JsonSerializable
public Bill $bill;
// Distribution of lots/sn and from which stock location
public array $identifiers = [];
/**
* Constructor.
*
@ -137,6 +173,8 @@ class BillElement implements \JsonSerializable
{
$this->bill = new NullBill();
$this->quantity = new FloatInt(FloatInt::DIVISOR);
$this->singleListPriceNet = new FloatInt();
$this->singleListPriceGross = new FloatInt();
@ -146,40 +184,26 @@ class BillElement implements \JsonSerializable
$this->singleSalesPriceNet = new FloatInt();
$this->singleSalesPriceGross = new FloatInt();
$this->effectiveSingleSalesPriceNet = new FloatInt();
$this->totalSalesPriceNet = new FloatInt();
$this->totalSalesPriceGross = new FloatInt();
$this->singlePurchasePriceNet = new FloatInt();
$this->singlePurchasePriceGross = new FloatInt();
$this->singlePurchasePriceNet = new FloatInt();
$this->totalPurchasePriceNet = new FloatInt();
$this->totalPurchasePriceNet = new FloatInt();
$this->totalPurchasePriceGross = new FloatInt();
$this->singleProfitNet = new FloatInt();
$this->singleProfitGross = new FloatInt();
$this->totalProfitNet = new FloatInt();
$this->totalProfitGross = new FloatInt();
$this->singleProfitNet = new FloatInt();
$this->totalProfitNet = new FloatInt();
$this->singleDiscountP = new FloatInt();
$this->totalDiscountP = new FloatInt();
$this->singleDiscountR = new FloatInt();
$this->discountQ = new FloatInt();
$this->taxP = new FloatInt();
$this->taxR = new FloatInt();
}
/**
* Get id.
*
* @return int Model id
*
* @since 1.0.0
*/
public function getId() : int
{
return $this->id;
}
/**
* Set the element quantity.
*
@ -191,24 +215,172 @@ class BillElement implements \JsonSerializable
*/
public function setQuantity(int $quantity) : void
{
if ($this->quantity === $quantity) {
if ($this->quantity->value === $quantity) {
return;
}
$this->quantity = $quantity;
// @todo: recalculate all the prices!!!
$this->quantity->value = $quantity;
$this->recalculatePrices();
}
/**
* Get quantity.
* Re-calculate prices.
*
* @return int
* This function is very important to call after changing any prices/quantities
*
* @return void
*
* @since 1.0.0
*/
public function getQuantity() : int
public function recalculatePrices() : void
{
return $this->quantity;
$rd = -FloatInt::MAX_DECIMALS + ISO4217DecimalEnum::getByName('_' . $this->bill->currency);
$this->totalListPriceNet->value = (int) \round($this->quantity->getNormalizedValue() * $this->singleListPriceNet->value, $rd);
$this->totalSalesPriceNet->value = (int) \round(($this->quantity->getNormalizedValue() - $this->discountQ->getNormalizedValue()) * $this->singleListPriceNet->value, $rd);
// @todo Check if this is correct, this should maybe happen after applying the discounts?!
// This depends on if the single price is already discounted or not
$this->singleProfitNet->value = $this->singleSalesPriceNet->value - $this->singlePurchasePriceNet->value;
$this->totalProfitNet->value = $this->totalSalesPriceNet->value - $this->totalPurchasePriceNet->value;
$this->taxP->value = (int) \round($this->taxR->value / (FloatInt::DIVISOR * 100) * $this->totalSalesPriceNet->value, $rd);
$this->singleListPriceGross->value = (int) \round($this->singleListPriceNet->value + $this->singleListPriceNet->value * $this->taxR->value / (FloatInt::DIVISOR * 100), $rd);
$this->totalListPriceGross->value = (int) \round($this->totalListPriceNet->value + $this->totalListPriceNet->value * $this->taxR->value / (FloatInt::DIVISOR * 100), $rd);
$this->singleSalesPriceGross->value = (int) \round($this->singleSalesPriceNet->value + $this->singleSalesPriceNet->value * $this->taxR->value / (FloatInt::DIVISOR * 100), $rd);
$this->totalSalesPriceGross->value = (int) \round($this->totalSalesPriceNet->value + $this->totalSalesPriceNet->value * $this->taxR->value / (FloatInt::DIVISOR * 100), $rd);
$this->singleDiscountP->value = $this->quantity->value - $this->discountQ->value === 0
? 0
: (int) \round($this->totalDiscountP->value / ($this->quantity->getNormalizedValue() - $this->discountQ->getNormalizedValue()));
// important because the quantity includes $discountQ
$this->effectiveSingleSalesPriceNet->value = (int) \round($this->totalSalesPriceNet->value / ($this->quantity->value / FloatInt::DIVISOR), $rd);
}
/**
* Validate the correctness of the element
*
* @return bool
*
* @todo also consider rounding similarly to recalculatePrices
*
* @since 1.0.0
*/
public function isValid() : bool
{
return $this->validateNetGross()
&& $this->validateProfit()
&& $this->validateTax()
&& $this->validateTaxRate()
&& $this->validateSingleTotal()
&& $this->validateEffectiveSinglePrice()
&& $this->validateTotalPrice();
}
/**
* Validate the correctness of the net and gross values
*
* @return bool
*
* @since 1.0.0
*/
public function validateNetGross() : bool
{
return $this->singleListPriceNet->value <= $this->singleListPriceGross->value
&& $this->singleSalesPriceNet->value <= $this->singleSalesPriceGross->value
&& $this->totalListPriceNet->value <= $this->totalListPriceGross->value
&& $this->totalSalesPriceNet->value <= $this->totalSalesPriceGross->value;
}
/**
* Validate the correctness of the profit
*
* @return bool
*
* @since 1.0.0
*/
public function validateProfit() : bool
{
return $this->totalSalesPriceNet->value - $this->totalPurchasePriceNet->value === $this->totalProfitNet->value;
}
/**
* Validate the correctness of the taxes
*
* @return bool
*
* @since 1.0.0
*/
public function validateTax() : bool
{
$paidQuantity = $this->quantity->value - $this->discountQ->value;
return \abs($this->singleListPriceNet->value + ((int) \round($this->taxP->value / ($paidQuantity / FloatInt::DIVISOR), 0)) - $this->singleListPriceGross->value) === 0
&& \abs($this->singleSalesPriceNet->value + ((int) \round($this->taxP->value / ($paidQuantity / FloatInt::DIVISOR), 0)) - $this->singleSalesPriceGross->value) === 0
&& \abs($this->totalListPriceNet->value + $this->taxP->value - $this->totalListPriceGross->value) === 0
&& \abs($this->totalSalesPriceNet->value + $this->taxP->value - $this->totalSalesPriceGross->value) === 0;
}
/**
* Validate the correctness of the tax rate
*
* @return bool
*
* @since 1.0.0
*/
public function validateTaxRate() : bool
{
return (($this->taxP->value === 0 && $this->taxR->value === 0)
|| (\abs($this->taxP->value / $this->totalSalesPriceNet->value - $this->taxR->value / (FloatInt::DIVISOR * 100)) < 0.001)
&& \abs($this->totalSalesPriceGross->value / $this->totalSalesPriceNet->value - 1.0 - $this->taxR->value / (FloatInt::DIVISOR * 100)) < 0.001);
}
/**
* Validate the correctness of single and total prices
*
* @return bool
*
* @since 1.0.0
*/
public function validateSingleTotal() : bool
{
$paidQuantity = $this->quantity->value - $this->discountQ->value;
// Only possible for sales, costs may be different for different lots
return ((int) \round($this->singleListPriceNet->value * ($this->quantity->value / FloatInt::DIVISOR), 0)) === $this->totalListPriceNet->value
&& ((int) \round($this->singleSalesPriceNet->value * ($paidQuantity / FloatInt::DIVISOR), 0)) === $this->totalSalesPriceNet->value
&& ((int) \round($this->singleDiscountP->value * ($this->quantity->value / FloatInt::DIVISOR), 0)) === $this->totalDiscountP->value;
}
/**
* Validate the correctness of the effective price
*
* @return bool
*
* @since 1.0.0
*/
public function validateEffectiveSinglePrice() : bool
{
return $this->effectiveSingleSalesPriceNet->value === (int) \round($this->totalSalesPriceNet->value / ($this->quantity->value / FloatInt::DIVISOR));
}
/**
* Validate the correctness of the total price
*
* @return bool
*
* @since 1.0.0
*/
public function validateTotalPrice() : bool
{
return ((int) \round($this->singleListPriceNet->value * ($this->quantity->value / FloatInt::DIVISOR)
- $this->singleListPriceNet->value * ($this->quantity->value / FloatInt::DIVISOR) * $this->singleDiscountR->value / (FloatInt::DIVISOR * 100)
- $this->totalDiscountP->value * ($this->quantity->value / FloatInt::DIVISOR)
- $this->singleListPriceNet->value * ($this->discountQ->value / FloatInt::DIVISOR), 0))
=== $this->totalSalesPriceNet->value;
}
/**
@ -222,56 +394,47 @@ class BillElement implements \JsonSerializable
*/
public function setItem(int $item) : void
{
$this->item = $item;
$this->item = new NullItem($item);
}
/**
* Create element from item
*
* @param Item $item Item
* @param TaxCode $code Tax code used for gross amount calculation
* @param int $quantity Quantity
* @param int $bill Bill
* @param Item $item Item
* @param TaxCombination $taxCombination Tax combination
* @param Bill $bill Bill
* @param int $quantity Quantity (1.0 = 10000)
* @param null|Container $container Item container
*
* @return self
*
* @since 1.0.0
*/
public static function fromItem(Item $item, TaxCode $code, int $quantity = 1, int $bill = 0) : self
public static function fromItem(
Item $item,
TaxCombination $taxCombination,
Bill $bill,
int $quantity = FloatInt::DIVISOR,
?Container $container = null
) : self
{
$element = new self();
$element->bill = new NullBill($bill);
$element->item = empty($item->id) ? null : $item->id;
$element->bill = $bill;
$element->item = empty($item->id) ? null : $item;
$element->container = empty($container->id) ? null : $container;
$element->itemNumber = $item->number;
$element->itemName = $item->getL11n('name1')->content;
$element->itemDescription = $item->getL11n('description_short')->content;
$element->quantity = $quantity;
$element->quantity->value = $quantity;
// @todo: Use pricing instead of the default sales price
// @todo: discounts might be in quantities
$element->singleListPriceNet->setInt($item->salesPrice->getInt());
$element->totalListPriceNet->setInt($element->quantity * $item->salesPrice->getInt());
$element->singleSalesPriceNet->setInt($item->salesPrice->getInt());
$element->totalSalesPriceNet->setInt($element->quantity * $item->salesPrice->getInt());
$element->singlePurchasePriceNet->setInt($item->purchasePrice->getInt());
$element->totalPurchasePriceNet->setInt($element->quantity * $item->purchasePrice->getInt());
$element->taxR = new FloatInt($taxCombination->taxCode->percentageInvoice);
$element->taxCode = $taxCombination->taxCode->abbr;
$element->fiAccount = $taxCombination->account;
$element->taxCombination = $taxCombination;
$element->singleProfitNet->setInt($element->singleSalesPriceNet->getInt() - $element->singlePurchasePriceNet->getInt());
$element->totalProfitNet->setInt($element->totalSalesPriceNet->getInt() - $element->totalPurchasePriceNet->getInt());
$element->taxP = new FloatInt((int) (($code->percentageInvoice * $element->totalSalesPriceNet->getInt()) / 10000));
$element->taxR = new FloatInt($code->percentageInvoice);
$element->taxCode = $code->abbr;
$element->singleListPriceGross->setInt((int) ($element->singleListPriceNet->getInt() + $element->singleListPriceNet->getInt() * $element->taxR->getInt() / 10000));
$element->totalListPriceGross->setInt((int) ($element->totalListPriceNet->getInt() + $element->totalListPriceNet->getInt() * $element->taxR->getInt() / 10000));
$element->singleSalesPriceGross->setInt((int) ($element->singleSalesPriceNet->getInt() + $element->singleSalesPriceNet->getInt() * $element->taxR->getInt() / 10000));
$element->totalSalesPriceGross->setInt((int) ($element->totalSalesPriceNet->getInt() + $element->totalSalesPriceNet->getInt() * $element->taxR->getInt() / 10000));
$element->singlePurchasePriceGross->setInt((int) ($element->singlePurchasePriceNet->getInt() + $element->singlePurchasePriceNet->getInt() * $element->taxR->getInt() / 10000));
$element->totalPurchasePriceGross->setInt((int) ($element->totalPurchasePriceNet->getInt() + $element->totalPurchasePriceNet->getInt() * $element->taxR->getInt() / 10000));
$element->singleProfitGross->setInt($element->singleSalesPriceGross->getInt() - $element->singlePurchasePriceGross->getInt());
$element->totalProfitGross->setInt($element->quantity * ($element->totalSalesPriceGross->getInt() - $element->totalPurchasePriceGross->getInt()));
// @todo the purchase price is based on lot/sn/avg prices if available
$element->singlePurchasePriceNet->value = $item->purchasePrice->value;
$element->totalPurchasePriceNet->value = (int) ($element->quantity->getNormalizedValue() * $item->purchasePrice->value);
if ($element->bill->id !== 0
&& $item->getAttribute('subscription')->value->getValue() === 1
@ -279,10 +442,9 @@ class BillElement implements \JsonSerializable
) {
$element->subscription = new Subscription();
$element->subscription->bill = $element->bill->id;
$element->subscription->item = $element->item;
$element->subscription->start = new \DateTime('now'); // @todo: change to bill performanceDate
$element->subscription->end = new SmartDateTime('now'); // @todo: depends on subscription type
$element->subscription->end->smartModify(m: 1);
$element->subscription->item = $element->item->id;
$element->subscription->start = $bill?->performanceDate ?? new \DateTime('now');
$element->subscription->end = (new SmartDateTime('now'))->smartModify(m: 1); // @todo depends on subscription type
$element->subscription->quantity = $element->quantity;
$element->subscription->autoRenew = $item->getAttribute('subscription_renewal_type')->value->getValue() === 1;
@ -299,7 +461,7 @@ class BillElement implements \JsonSerializable
return [
'id' => $this->id,
'order' => $this->order,
'item' => $this->item,
'item' => $this->item?->id,
'itemNumber' => $this->itemNumber,
'itemName' => $this->itemName,
'itemDescription' => $this->itemDescription,

View File

@ -14,6 +14,9 @@ declare(strict_types=1);
namespace Modules\Billing\Models;
use Modules\Billing\Models\Tax\TaxCombinationMapper;
use Modules\ItemManagement\Models\ContainerMapper;
use Modules\ItemManagement\Models\ItemMapper;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
/**
@ -36,38 +39,47 @@ final class BillElementMapper extends DataMapperFactory
* @since 1.0.0
*/
public const COLUMNS = [
'billing_bill_element_id' => ['name' => 'billing_bill_element_id', 'type' => 'int', 'internal' => 'id'],
'billing_bill_element_order' => ['name' => 'billing_bill_element_order', 'type' => 'int', 'internal' => 'order'],
'billing_bill_element_item' => ['name' => 'billing_bill_element_item', 'type' => 'int', 'internal' => 'item'],
'billing_bill_element_item_number' => ['name' => 'billing_bill_element_item_number', 'type' => 'string', 'internal' => 'itemNumber'],
'billing_bill_element_item_name' => ['name' => 'billing_bill_element_item_name', 'type' => 'string', 'internal' => 'itemName'],
'billing_bill_element_item_desc' => ['name' => 'billing_bill_element_item_desc', 'type' => 'string', 'internal' => 'itemDescription'],
'billing_bill_element_quantity' => ['name' => 'billing_bill_element_quantity', 'type' => 'int', 'internal' => 'quantity', 'private' => true],
'billing_bill_element_id' => ['name' => 'billing_bill_element_id', 'type' => 'int', 'internal' => 'id'],
'billing_bill_element_order' => ['name' => 'billing_bill_element_order', 'type' => 'int', 'internal' => 'order'],
'billing_bill_element_item' => ['name' => 'billing_bill_element_item', 'type' => 'int', 'internal' => 'item'],
'billing_bill_element_container' => ['name' => 'billing_bill_element_container', 'type' => 'int', 'internal' => 'container'],
'billing_bill_element_item_number' => ['name' => 'billing_bill_element_item_number', 'type' => 'string', 'internal' => 'itemNumber'],
'billing_bill_element_item_name' => ['name' => 'billing_bill_element_item_name', 'type' => 'string', 'internal' => 'itemName'],
'billing_bill_element_item_desc' => ['name' => 'billing_bill_element_item_desc', 'type' => 'string', 'internal' => 'itemDescription'],
'billing_bill_element_quantity' => ['name' => 'billing_bill_element_quantity', 'type' => 'Serializable', 'internal' => 'quantity', 'private' => true],
'billing_bill_element_single_netlistprice' => ['name' => 'billing_bill_element_single_netlistprice', 'type' => 'Serializable', 'internal' => 'singleListPriceNet'],
'billing_bill_element_single_grosslistprice' => ['name' => 'billing_bill_element_single_grosslistprice', 'type' => 'Serializable', 'internal' => 'singleListPriceGross'],
'billing_bill_element_total_netlistprice' => ['name' => 'billing_bill_element_total_netlistprice', 'type' => 'Serializable', 'internal' => 'totalListPriceNet'],
'billing_bill_element_total_grosslistprice' => ['name' => 'billing_bill_element_total_grosslistprice', 'type' => 'Serializable', 'internal' => 'totalListPriceGross'],
'billing_bill_element_single_netlistprice' => ['name' => 'billing_bill_element_single_netlistprice', 'type' => 'Serializable', 'internal' => 'singleListPriceNet'],
'billing_bill_element_single_grosslistprice' => ['name' => 'billing_bill_element_single_grosslistprice', 'type' => 'Serializable', 'internal' => 'singleListPriceGross'],
'billing_bill_element_total_netlistprice' => ['name' => 'billing_bill_element_total_netlistprice', 'type' => 'Serializable', 'internal' => 'totalListPriceNet'],
'billing_bill_element_total_grosslistprice' => ['name' => 'billing_bill_element_total_grosslistprice', 'type' => 'Serializable', 'internal' => 'totalListPriceGross'],
'billing_bill_element_single_netsalesprice' => ['name' => 'billing_bill_element_single_netsalesprice', 'type' => 'Serializable', 'internal' => 'singleSalesPriceNet'],
'billing_bill_element_single_grosssalesprice' => ['name' => 'billing_bill_element_single_grosssalesprice', 'type' => 'Serializable', 'internal' => 'singleSalesPriceGross'],
'billing_bill_element_total_netsalesprice' => ['name' => 'billing_bill_element_total_netsalesprice', 'type' => 'Serializable', 'internal' => 'totalSalesPriceNet'],
'billing_bill_element_total_grosssalesprice' => ['name' => 'billing_bill_element_total_grosssalesprice', 'type' => 'Serializable', 'internal' => 'totalSalesPriceGross'],
'billing_bill_element_single_netsalesprice' => ['name' => 'billing_bill_element_single_netsalesprice', 'type' => 'Serializable', 'internal' => 'singleSalesPriceNet'],
'billing_bill_element_single_effectivenetsalesprice' => ['name' => 'billing_bill_element_single_effectivenetsalesprice', 'type' => 'Serializable', 'internal' => 'effectiveSingleSalesPriceNet'],
'billing_bill_element_single_grosssalesprice' => ['name' => 'billing_bill_element_single_grosssalesprice', 'type' => 'Serializable', 'internal' => 'singleSalesPriceGross'],
'billing_bill_element_total_netsalesprice' => ['name' => 'billing_bill_element_total_netsalesprice', 'type' => 'Serializable', 'internal' => 'totalSalesPriceNet'],
'billing_bill_element_total_grosssalesprice' => ['name' => 'billing_bill_element_total_grosssalesprice', 'type' => 'Serializable', 'internal' => 'totalSalesPriceGross'],
'billing_bill_element_single_netprofit' => ['name' => 'billing_bill_element_single_netprofit', 'type' => 'Serializable', 'internal' => 'singleProfitNet'],
'billing_bill_element_single_grossprofit' => ['name' => 'billing_bill_element_single_grossprofit', 'type' => 'Serializable', 'internal' => 'singleProfitGross'],
'billing_bill_element_total_netprofit' => ['name' => 'billing_bill_element_total_netprofit', 'type' => 'Serializable', 'internal' => 'totalProfitNet'],
'billing_bill_element_total_grossprofit' => ['name' => 'billing_bill_element_total_grossprofit', 'type' => 'Serializable', 'internal' => 'totalProfitGross'],
'billing_bill_element_single_netprofit' => ['name' => 'billing_bill_element_single_netprofit', 'type' => 'Serializable', 'internal' => 'singleProfitNet'],
'billing_bill_element_total_netprofit' => ['name' => 'billing_bill_element_total_netprofit', 'type' => 'Serializable', 'internal' => 'totalProfitNet'],
'billing_bill_element_single_netpurchaseprice' => ['name' => 'billing_bill_element_single_netpurchaseprice', 'type' => 'Serializable', 'internal' => 'singlePurchasePriceNet'],
'billing_bill_element_single_grosspurchaseprice' => ['name' => 'billing_bill_element_single_grosspurchaseprice', 'type' => 'Serializable', 'internal' => 'singlePurchasePriceGross'],
'billing_bill_element_total_netpurchaseprice' => ['name' => 'billing_bill_element_total_netpurchaseprice', 'type' => 'Serializable', 'internal' => 'totalPurchasePriceNet'],
'billing_bill_element_total_grosspurchaseprice' => ['name' => 'billing_bill_element_total_grosspurchaseprice', 'type' => 'Serializable', 'internal' => 'totalPurchasePriceGross'],
'billing_bill_element_bill' => ['name' => 'billing_bill_element_bill', 'type' => 'int', 'internal' => 'bill'],
'billing_bill_element_single_netpurchaseprice' => ['name' => 'billing_bill_element_single_netpurchaseprice', 'type' => 'Serializable', 'internal' => 'singlePurchasePriceNet'],
'billing_bill_element_total_netpurchaseprice' => ['name' => 'billing_bill_element_total_netpurchaseprice', 'type' => 'Serializable', 'internal' => 'totalPurchasePriceNet'],
'billing_bill_element_bill' => ['name' => 'billing_bill_element_bill', 'type' => 'int', 'internal' => 'bill'],
'billing_bill_element_tax_type' => ['name' => 'billing_bill_element_tax_type', 'type' => 'string', 'internal' => 'taxCode'],
'billing_bill_element_tax_price' => ['name' => 'billing_bill_element_tax_price', 'type' => 'Serializable', 'internal' => 'taxP'],
'billing_bill_element_tax_percentage' => ['name' => 'billing_bill_element_tax_percentage', 'type' => 'Serializable', 'internal' => 'taxR'],
'billing_bill_element_tax_combination' => ['name' => 'billing_bill_element_tax_combination', 'type' => 'int', 'internal' => 'taxCombination'],
'billing_bill_element_tax_type' => ['name' => 'billing_bill_element_tax_type', 'type' => 'string', 'internal' => 'taxCode'],
'billing_bill_element_tax_price' => ['name' => 'billing_bill_element_tax_price', 'type' => 'Serializable', 'internal' => 'taxP'],
'billing_bill_element_tax_percentage' => ['name' => 'billing_bill_element_tax_percentage', 'type' => 'Serializable', 'internal' => 'taxR'],
'billing_bill_element_segment' => ['name' => 'billing_bill_element_segment', 'type' => 'int', 'internal' => 'itemSegment'],
'billing_bill_element_section' => ['name' => 'billing_bill_element_section', 'type' => 'int', 'internal' => 'itemSection'],
'billing_bill_element_salesgroup' => ['name' => 'billing_bill_element_salesgroup', 'type' => 'int', 'internal' => 'itemSalesGroup'],
'billing_bill_element_productgroup' => ['name' => 'billing_bill_element_productgroup', 'type' => 'int', 'internal' => 'itemProductGroup'],
'billing_bill_element_itemtype' => ['name' => 'billing_bill_element_itemtype', 'type' => 'int', 'internal' => 'itemType'],
'billing_bill_element_fiaccount' => ['name' => 'billing_bill_element_fiaccount', 'type' => 'string', 'internal' => 'fiAccount'],
'billing_bill_element_costcenter' => ['name' => 'billing_bill_element_costcenter', 'type' => 'string', 'internal' => 'costcenter'],
'billing_bill_element_costobject' => ['name' => 'billing_bill_element_costobject', 'type' => 'string', 'internal' => 'costobject'],
];
/**
@ -78,8 +90,8 @@ final class BillElementMapper extends DataMapperFactory
*/
public const BELONGS_TO = [
'bill' => [
'mapper' => BillMapper::class,
'external' => 'billing_bill_element_bill',
'mapper' => BillMapper::class,
'external' => 'billing_bill_element_bill',
],
];
@ -91,8 +103,20 @@ final class BillElementMapper extends DataMapperFactory
*/
public const OWNS_ONE = [
'subscription' => [
'mapper' => SubscriptionMapper::class,
'external' => 'billing_bill_element_subscription',
'mapper' => SubscriptionMapper::class,
'external' => 'billing_bill_element_subscription',
],
'item' => [
'mapper' => ItemMapper::class,
'external' => 'billing_bill_element_item',
],
'container' => [
'mapper' => ContainerMapper::class,
'external' => 'billing_bill_element_container',
],
'taxCombination' => [
'mapper' => TaxCombinationMapper::class,
'external' => 'billing_bill_element_tax_combination',
],
];

View File

@ -45,55 +45,60 @@ class BillMapper extends DataMapperFactory
* @since 1.0.0
*/
public const COLUMNS = [
'billing_bill_id' => ['name' => 'billing_bill_id', 'type' => 'int', 'internal' => 'id'],
'billing_bill_sequence' => ['name' => 'billing_bill_sequence', 'type' => 'int', 'internal' => 'sequence'],
'billing_bill_number' => ['name' => 'billing_bill_number', 'type' => 'string', 'internal' => 'number'],
'billing_bill_type' => ['name' => 'billing_bill_type', 'type' => 'int', 'internal' => 'type'],
'billing_bill_template' => ['name' => 'billing_bill_template', 'type' => 'int', 'internal' => 'template'],
'billing_bill_header' => ['name' => 'billing_bill_header', 'type' => 'string', 'internal' => 'header'],
'billing_bill_footer' => ['name' => 'billing_bill_footer', 'type' => 'string', 'internal' => 'footer'],
'billing_bill_info' => ['name' => 'billing_bill_info', 'type' => 'string', 'internal' => 'info'],
'billing_bill_status' => ['name' => 'billing_bill_status', 'type' => 'int', 'internal' => 'status'],
'billing_bill_paymentstatus' => ['name' => 'billing_bill_paymentstatus', 'type' => 'int', 'internal' => 'paymentStatus'],
'billing_bill_shipTo' => ['name' => 'billing_bill_shipTo', 'type' => 'string', 'internal' => 'shipTo'],
'billing_bill_shipFAO' => ['name' => 'billing_bill_shipFAO', 'type' => 'string', 'internal' => 'shipFAO'],
'billing_bill_shipAddr' => ['name' => 'billing_bill_shipAddr', 'type' => 'string', 'internal' => 'shipAddress'],
'billing_bill_shipCity' => ['name' => 'billing_bill_shipCity', 'type' => 'string', 'internal' => 'shipCity'],
'billing_bill_shipZip' => ['name' => 'billing_bill_shipZip', 'type' => 'string', 'internal' => 'shipZip'],
'billing_bill_shipCountry' => ['name' => 'billing_bill_shipCountry', 'type' => 'string', 'internal' => 'shipCountry'],
'billing_bill_billTo' => ['name' => 'billing_bill_billTo', 'type' => 'string', 'internal' => 'billTo'],
'billing_bill_billFAO' => ['name' => 'billing_bill_billFAO', 'type' => 'string', 'internal' => 'billFAO'],
'billing_bill_billAddr' => ['name' => 'billing_bill_billAddr', 'type' => 'string', 'internal' => 'billAddress'],
'billing_bill_billCity' => ['name' => 'billing_bill_billCity', 'type' => 'string', 'internal' => 'billCity'],
'billing_bill_billZip' => ['name' => 'billing_bill_billZip', 'type' => 'string', 'internal' => 'billZip'],
'billing_bill_billCountry' => ['name' => 'billing_bill_billCountry', 'type' => 'string', 'internal' => 'billCountry'],
'billing_bill_netprofit' => ['name' => 'billing_bill_netprofit', 'type' => 'Serializable', 'internal' => 'netProfit'],
'billing_bill_grossprofit' => ['name' => 'billing_bill_grossprofit', 'type' => 'Serializable', 'internal' => 'grossProfit'],
'billing_bill_netcosts' => ['name' => 'billing_bill_netcosts', 'type' => 'Serializable', 'internal' => 'netCosts'],
'billing_bill_grosscosts' => ['name' => 'billing_bill_grosscosts', 'type' => 'Serializable', 'internal' => 'grossCosts'],
'billing_bill_netsales' => ['name' => 'billing_bill_netsales', 'type' => 'Serializable', 'internal' => 'netSales'],
'billing_bill_grosssales' => ['name' => 'billing_bill_grosssales', 'type' => 'Serializable', 'internal' => 'grossSales'],
'billing_bill_netdiscount' => ['name' => 'billing_bill_netdiscount', 'type' => 'Serializable', 'internal' => 'netDiscount'],
'billing_bill_grossdiscount' => ['name' => 'billing_bill_grossdiscount', 'type' => 'Serializable', 'internal' => 'grossDiscount'],
'billing_bill_currency' => ['name' => 'billing_bill_currency', 'type' => 'string', 'internal' => 'currency'],
'billing_bill_language' => ['name' => 'billing_bill_language', 'type' => 'string', 'internal' => 'language'],
'billing_bill_referral' => ['name' => 'billing_bill_referral', 'type' => 'int', 'internal' => 'referral'],
'billing_bill_referral_name' => ['name' => 'billing_bill_referral_name', 'type' => 'string', 'internal' => 'referralName'],
'billing_bill_reference' => ['name' => 'billing_bill_reference', 'type' => 'int', 'internal' => 'reference'],
'billing_bill_payment' => ['name' => 'billing_bill_payment', 'type' => 'int', 'internal' => 'payment'],
'billing_bill_payment_text' => ['name' => 'billing_bill_payment_text', 'type' => 'string', 'internal' => 'paymentText'],
'billing_bill_paymentterms' => ['name' => 'billing_bill_paymentterms', 'type' => 'int', 'internal' => 'terms'],
'billing_bill_paymentterms_text' => ['name' => 'billing_bill_paymentterms_text', 'type' => 'string', 'internal' => 'termsText'],
'billing_bill_ship_type' => ['name' => 'billing_bill_ship_type', 'type' => 'int', 'internal' => 'shipping'],
'billing_bill_ship_text' => ['name' => 'billing_bill_ship_text', 'type' => 'string', 'internal' => 'shippingText'],
'billing_bill_account_no' => ['name' => 'billing_bill_account_no', 'type' => 'string', 'internal' => 'accountNumber'],
'billing_bill_client' => ['name' => 'billing_bill_client', 'type' => 'int', 'internal' => 'client'],
'billing_bill_supplier' => ['name' => 'billing_bill_supplier', 'type' => 'int', 'internal' => 'supplier'],
'billing_bill_created_by' => ['name' => 'billing_bill_created_by', 'type' => 'int', 'internal' => 'createdBy', 'readonly' => true],
'billing_bill_date' => ['name' => 'billing_bill_date', 'type' => 'DateTime', 'internal' => 'billDate'],
'billing_bill_performance_date' => ['name' => 'billing_bill_performance_date', 'type' => 'DateTime', 'internal' => 'performanceDate', 'readonly' => true],
'billing_bill_created_at' => ['name' => 'billing_bill_created_at', 'type' => 'DateTimeImmutable', 'internal' => 'createdAt', 'readonly' => true],
'billing_bill_unit' => ['name' => 'billing_bill_unit', 'type' => 'int', 'internal' => 'unit'],
'billing_bill_id' => ['name' => 'billing_bill_id', 'type' => 'int', 'internal' => 'id'],
'billing_bill_sequence' => ['name' => 'billing_bill_sequence', 'type' => 'int', 'internal' => 'sequence'],
'billing_bill_number' => ['name' => 'billing_bill_number', 'type' => 'string', 'internal' => 'number'],
'billing_bill_external' => ['name' => 'billing_bill_external', 'type' => 'string', 'internal' => 'external'],
'billing_bill_type' => ['name' => 'billing_bill_type', 'type' => 'int', 'internal' => 'type'],
'billing_bill_template' => ['name' => 'billing_bill_template', 'type' => 'bool', 'internal' => 'isTemplate'],
'billing_bill_archived' => ['name' => 'billing_bill_archived', 'type' => 'bool', 'internal' => 'isArchived'],
'billing_bill_header' => ['name' => 'billing_bill_header', 'type' => 'string', 'internal' => 'header'],
'billing_bill_footer' => ['name' => 'billing_bill_footer', 'type' => 'string', 'internal' => 'footer'],
'billing_bill_info' => ['name' => 'billing_bill_info', 'type' => 'string', 'internal' => 'info'],
'billing_bill_status' => ['name' => 'billing_bill_status', 'type' => 'int', 'internal' => 'status'],
'billing_bill_paymentstatus' => ['name' => 'billing_bill_paymentstatus', 'type' => 'int', 'internal' => 'paymentStatus'],
'billing_bill_shipTo' => ['name' => 'billing_bill_shipTo', 'type' => 'string', 'internal' => 'shipTo'],
'billing_bill_shipFAO' => ['name' => 'billing_bill_shipFAO', 'type' => 'string', 'internal' => 'shipFAO'],
'billing_bill_shipAddr' => ['name' => 'billing_bill_shipAddr', 'type' => 'string', 'internal' => 'shipAddress'],
'billing_bill_shipCity' => ['name' => 'billing_bill_shipCity', 'type' => 'string', 'internal' => 'shipCity'],
'billing_bill_shipZip' => ['name' => 'billing_bill_shipZip', 'type' => 'string', 'internal' => 'shipZip'],
'billing_bill_shipCountry' => ['name' => 'billing_bill_shipCountry', 'type' => 'string', 'internal' => 'shipCountry'],
'billing_bill_billTo' => ['name' => 'billing_bill_billTo', 'type' => 'string', 'internal' => 'billTo'],
'billing_bill_billFAO' => ['name' => 'billing_bill_billFAO', 'type' => 'string', 'internal' => 'billFAO'],
'billing_bill_billAddr' => ['name' => 'billing_bill_billAddr', 'type' => 'string', 'internal' => 'billAddress'],
'billing_bill_billCity' => ['name' => 'billing_bill_billCity', 'type' => 'string', 'internal' => 'billCity'],
'billing_bill_billZip' => ['name' => 'billing_bill_billZip', 'type' => 'string', 'internal' => 'billZip'],
'billing_bill_billCountry' => ['name' => 'billing_bill_billCountry', 'type' => 'string', 'internal' => 'billCountry'],
'billing_bill_netprofit' => ['name' => 'billing_bill_netprofit', 'type' => 'Serializable', 'internal' => 'netProfit'],
'billing_bill_netcosts' => ['name' => 'billing_bill_netcosts', 'type' => 'Serializable', 'internal' => 'netCosts'],
'billing_bill_netsales' => ['name' => 'billing_bill_netsales', 'type' => 'Serializable', 'internal' => 'netSales'],
'billing_bill_grosssales' => ['name' => 'billing_bill_grosssales', 'type' => 'Serializable', 'internal' => 'grossSales'],
'billing_bill_netdiscount' => ['name' => 'billing_bill_netdiscount', 'type' => 'Serializable', 'internal' => 'netDiscount'],
'billing_bill_taxp' => ['name' => 'billing_bill_taxp', 'type' => 'Serializable', 'internal' => 'taxP'],
'billing_bill_fiaccount' => ['name' => 'billing_bill_fiaccount', 'type' => 'string', 'internal' => 'fiAccount'],
'billing_bill_currency' => ['name' => 'billing_bill_currency', 'type' => 'string', 'internal' => 'currency'],
'billing_bill_language' => ['name' => 'billing_bill_language', 'type' => 'string', 'internal' => 'language'],
'billing_bill_referral' => ['name' => 'billing_bill_referral', 'type' => 'int', 'internal' => 'referral'],
'billing_bill_reference' => ['name' => 'billing_bill_reference', 'type' => 'int', 'internal' => 'reference'],
'billing_bill_accsegment' => ['name' => 'billing_bill_accsegment', 'type' => 'int', 'internal' => 'accSegment'],
'billing_bill_accsection' => ['name' => 'billing_bill_accsection', 'type' => 'int', 'internal' => 'accSection'],
'billing_bill_accgroup' => ['name' => 'billing_bill_accgroup', 'type' => 'int', 'internal' => 'accGroup'],
'billing_bill_acctype' => ['name' => 'billing_bill_acctype', 'type' => 'int', 'internal' => 'accType'],
'billing_bill_payment' => ['name' => 'billing_bill_payment', 'type' => 'int', 'internal' => 'payment'],
'billing_bill_payment_text' => ['name' => 'billing_bill_payment_text', 'type' => 'string', 'internal' => 'paymentText'],
'billing_bill_paymentterms' => ['name' => 'billing_bill_paymentterms', 'type' => 'int', 'internal' => 'paymentTerms'],
'billing_bill_paymentterms_text' => ['name' => 'billing_bill_paymentterms_text', 'type' => 'string', 'internal' => 'termsText'],
'billing_bill_ship_type' => ['name' => 'billing_bill_ship_type', 'type' => 'int', 'internal' => 'shippingTerms'],
'billing_bill_ship_text' => ['name' => 'billing_bill_ship_text', 'type' => 'string', 'internal' => 'shippingText'],
'billing_bill_account_no' => ['name' => 'billing_bill_account_no', 'type' => 'string', 'internal' => 'accountNumber'],
'billing_bill_tax_type' => ['name' => 'billing_bill_tax_type', 'type' => 'int', 'internal' => 'accTaxCode'],
'billing_bill_client' => ['name' => 'billing_bill_client', 'type' => 'int', 'internal' => 'client'],
'billing_bill_supplier' => ['name' => 'billing_bill_supplier', 'type' => 'int', 'internal' => 'supplier'],
'billing_bill_created_by' => ['name' => 'billing_bill_created_by', 'type' => 'int', 'internal' => 'createdBy', 'readonly' => true],
'billing_bill_date' => ['name' => 'billing_bill_date', 'type' => 'DateTime', 'internal' => 'billDate'],
'billing_bill_performance_date' => ['name' => 'billing_bill_performance_date', 'type' => 'DateTime', 'internal' => 'performanceDate', 'readonly' => true],
'billing_bill_created_at' => ['name' => 'billing_bill_created_at', 'type' => 'DateTimeImmutable', 'internal' => 'createdAt', 'readonly' => true],
'billing_bill_unit' => ['name' => 'billing_bill_unit', 'type' => 'int', 'internal' => 'unit'],
];
/**
@ -104,12 +109,12 @@ class BillMapper extends DataMapperFactory
*/
public const HAS_MANY = [
'elements' => [
'mapper' => BillElementMapper::class,
'table' => 'billing_bill_element',
'self' => 'billing_bill_element_bill',
'external' => null,
'mapper' => BillElementMapper::class,
'table' => 'billing_bill_element',
'self' => 'billing_bill_element_bill',
'external' => null,
],
'files' => [
'files' => [
'mapper' => MediaMapper::class,
'table' => 'billing_bill_media',
'external' => 'billing_bill_media_dst',
@ -130,17 +135,17 @@ class BillMapper extends DataMapperFactory
* @since 1.0.0
*/
public const OWNS_ONE = [
'type' => [
'mapper' => BillTypeMapper::class,
'external' => 'billing_bill_type',
'type' => [
'mapper' => BillTypeMapper::class,
'external' => 'billing_bill_type',
],
'referral' => [
'mapper' => AccountMapper::class,
'external' => 'billing_bill_referral',
'referral' => [
'mapper' => AccountMapper::class,
'external' => 'billing_bill_referral',
],
'template' => [
'mapper' => CollectionMapper::class,
'external' => 'billing_bill_template',
'template' => [
'mapper' => CollectionMapper::class,
'external' => 'billing_bill_template',
],
];
@ -152,16 +157,16 @@ class BillMapper extends DataMapperFactory
*/
public const BELONGS_TO = [
'createdBy' => [
'mapper' => AccountMapper::class,
'external' => 'billing_bill_created_by',
'mapper' => AccountMapper::class,
'external' => 'billing_bill_created_by',
],
'client' => [
'mapper' => ClientMapper::class,
'external' => 'billing_bill_client',
'mapper' => ClientMapper::class,
'external' => 'billing_bill_client',
],
'supplier' => [
'mapper' => SupplierMapper::class,
'external' => 'billing_bill_supplier',
'mapper' => SupplierMapper::class,
'external' => 'billing_bill_supplier',
],
'attributes' => [
'mapper' => BillAttributeMapper::class,

View File

@ -30,5 +30,7 @@ abstract class BillTransferType extends Enum
public const PURCHASE = 2;
public const PRODUCTION = 3;
public const STOCK = 4;
}

View File

@ -50,8 +50,12 @@ class BillType implements \JsonSerializable
public bool $transferStock = true;
public bool $isAccounting = false;
public int $sign = 1;
public bool $email = false;
/**
* Localization
*
@ -88,13 +92,13 @@ class BillType implements \JsonSerializable
if ($l11n instanceof BaseStringL11n) {
$this->l11n = $l11n;
} elseif (isset($this->l11n) && $this->l11n instanceof BaseStringL11n) {
$this->l11n->content = $l11n;
$this->l11n->setLanguage($lang);
$this->l11n->content = $l11n;
$this->l11n->language = $lang;
} else {
$this->l11n = new BaseStringL11n();
$this->l11n->content = $l11n;
$this->l11n->ref = $this->id;
$this->l11n->setLanguage($lang);
$this->l11n = new BaseStringL11n();
$this->l11n->content = $l11n;
$this->l11n->ref = $this->id;
$this->l11n->language = $lang;
}
}
@ -144,9 +148,9 @@ class BillType implements \JsonSerializable
public function toArray() : array
{
return [
'id' => $this->id,
'numberFormat' => $this->numberFormat,
'transferType' => $this->transferType,
'id' => $this->id,
'numberFormat' => $this->numberFormat,
'transferType' => $this->transferType,
];
}

View File

@ -37,10 +37,10 @@ final class BillTypeL11nMapper extends DataMapperFactory
* @since 1.0.0
*/
public const COLUMNS = [
'billing_type_l11n_id' => ['name' => 'billing_type_l11n_id', 'type' => 'int', 'internal' => 'id'],
'billing_type_l11n_name' => ['name' => 'billing_type_l11n_name', 'type' => 'string', 'internal' => 'content', 'autocomplete' => true],
'billing_type_l11n_type' => ['name' => 'billing_type_l11n_type', 'type' => 'int', 'internal' => 'ref'],
'billing_type_l11n_language' => ['name' => 'billing_type_l11n_language', 'type' => 'string', 'internal' => 'language'],
'billing_type_l11n_id' => ['name' => 'billing_type_l11n_id', 'type' => 'int', 'internal' => 'id'],
'billing_type_l11n_name' => ['name' => 'billing_type_l11n_name', 'type' => 'string', 'internal' => 'content', 'autocomplete' => true],
'billing_type_l11n_type' => ['name' => 'billing_type_l11n_type', 'type' => 'int', 'internal' => 'ref'],
'billing_type_l11n_language' => ['name' => 'billing_type_l11n_language', 'type' => 'string', 'internal' => 'language'],
];
/**

View File

@ -37,15 +37,17 @@ final class BillTypeMapper extends DataMapperFactory
* @since 1.0.0
*/
public const COLUMNS = [
'billing_type_id' => ['name' => 'billing_type_id', 'type' => 'int', 'internal' => 'id'],
'billing_type_name' => ['name' => 'billing_type_name', 'type' => 'string', 'internal' => 'name'],
'billing_type_number_format' => ['name' => 'billing_type_number_format', 'type' => 'string', 'internal' => 'numberFormat'],
'billing_type_account_format' => ['name' => 'billing_type_account_format', 'type' => 'string', 'internal' => 'accountFormat'],
'billing_type_transfer_type' => ['name' => 'billing_type_transfer_type', 'type' => 'int', 'internal' => 'transferType'],
'billing_type_default_template' => ['name' => 'billing_type_default_template', 'type' => 'int', 'internal' => 'defaultTemplate'],
'billing_type_transfer_stock' => ['name' => 'billing_type_transfer_stock', 'type' => 'bool', 'internal' => 'transferStock'],
'billing_type_transfer_sign' => ['name' => 'billing_type_transfer_sign', 'type' => 'int', 'internal' => 'sign'],
'billing_type_is_template' => ['name' => 'billing_type_is_template', 'type' => 'bool', 'internal' => 'isTemplate'],
'billing_type_id' => ['name' => 'billing_type_id', 'type' => 'int', 'internal' => 'id'],
'billing_type_name' => ['name' => 'billing_type_name', 'type' => 'string', 'internal' => 'name'],
'billing_type_number_format' => ['name' => 'billing_type_number_format', 'type' => 'string', 'internal' => 'numberFormat'],
'billing_type_account_format' => ['name' => 'billing_type_account_format', 'type' => 'string', 'internal' => 'accountFormat'],
'billing_type_transfer_type' => ['name' => 'billing_type_transfer_type', 'type' => 'int', 'internal' => 'transferType'],
'billing_type_default_template' => ['name' => 'billing_type_default_template', 'type' => 'int', 'internal' => 'defaultTemplate'],
'billing_type_transfer_stock' => ['name' => 'billing_type_transfer_stock', 'type' => 'bool', 'internal' => 'transferStock'],
'billing_type_accounting' => ['name' => 'billing_type_accounting', 'type' => 'bool', 'internal' => 'isAccounting'],
'billing_type_transfer_sign' => ['name' => 'billing_type_transfer_sign', 'type' => 'int', 'internal' => 'sign'],
'billing_type_email' => ['name' => 'billing_type_email', 'type' => 'bool', 'internal' => 'email'],
'billing_type_is_template' => ['name' => 'billing_type_is_template', 'type' => 'bool', 'internal' => 'isTemplate'],
];
/**
@ -56,13 +58,13 @@ final class BillTypeMapper extends DataMapperFactory
*/
public const HAS_MANY = [
'l11n' => [
'mapper' => BillTypeL11nMapper::class,
'table' => 'billing_type_l11n',
'self' => 'billing_type_l11n_type',
'column' => 'content',
'external' => null,
'mapper' => BillTypeL11nMapper::class,
'table' => 'billing_type_l11n',
'self' => 'billing_type_l11n_type',
'column' => 'content',
'external' => null,
],
'templates' => [
'templates' => [
'mapper' => CollectionMapper::class,
'table' => 'billing_bill_type_media_rel',
'external' => 'billing_bill_type_media_rel_dst',
@ -77,9 +79,9 @@ final class BillTypeMapper extends DataMapperFactory
* @since 1.0.0
*/
public const OWNS_ONE = [
'defaultTemplate' => [
'mapper' => CollectionMapper::class,
'external' => 'billing_type_default_template',
'defaultTemplate' => [
'mapper' => CollectionMapper::class,
'external' => 'billing_type_default_template',
],
];

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,69 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\Billing\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\Billing\Models;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
use phpOMS\Localization\BaseStringL11n;
/**
* Item mapper class.
*
* @package Modules\Billing\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @template T of BaseStringL11n
* @extends DataMapperFactory<T>
*/
final class PaymentTermL11nMapper extends DataMapperFactory
{
/**
* Columns.
*
* @var array<string, array{name:string, type:string, internal:string, autocomplete?:bool, readonly?:bool, writeonly?:bool, annotations?:array}>
* @since 1.0.0
*/
public const COLUMNS = [
'billing_payment_term_l11n_id' => ['name' => 'billing_payment_term_l11n_id', 'type' => 'int', 'internal' => 'id'],
'billing_payment_term_l11n_name' => ['name' => 'billing_payment_term_l11n_name', 'type' => 'string', 'internal' => 'content', 'autocomplete' => true],
'billing_payment_term_l11n_term' => ['name' => 'billing_payment_term_l11n_term', 'type' => 'int', 'internal' => 'ref'],
'billing_payment_term_l11n_language' => ['name' => 'billing_payment_term_l11n_language', 'type' => 'string', 'internal' => 'language'],
];
/**
* Primary table.
*
* @var string
* @since 1.0.0
*/
public const TABLE = 'billing_payment_term_l11n';
/**
* Primary field name.
*
* @var string
* @since 1.0.0
*/
public const PRIMARYFIELD = 'billing_payment_term_l11n_id';
/**
* Model to use by the mapper.
*
* @var class-string<T>
* @since 1.0.0
*/
public const MODEL = BaseStringL11n::class;
}

View File

@ -0,0 +1,83 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\Billing\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\Billing\Models;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
use phpOMS\Localization\BaseStringL11nType;
/**
* Item mapper class.
*
* @package Modules\Billing\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @template T of BaseStringL11nType
* @extends DataMapperFactory<T>
*/
final class PaymentTermMapper extends DataMapperFactory
{
/**
* Columns.
*
* @var array<string, array{name:string, type:string, internal:string, autocomplete?:bool, readonly?:bool, writeonly?:bool, annotations?:array}>
* @since 1.0.0
*/
public const COLUMNS = [
'billing_payment_term_id' => ['name' => 'billing_payment_term_id', 'type' => 'int', 'internal' => 'id'],
'billing_payment_term_code' => ['name' => 'billing_payment_term_code', 'type' => 'string', 'internal' => 'title', 'autocomplete' => true],
];
/**
* Has many relation.
*
* @var array<string, array{mapper:class-string, table:string, self?:?string, external?:?string, column?:string}>
* @since 1.0.0
*/
public const HAS_MANY = [
'l11n' => [
'mapper' => PaymentTermL11nMapper::class,
'table' => 'billing_payment_term_l11n',
'self' => 'billing_payment_term_l11n_term',
'column' => 'content',
'external' => null,
],
];
/**
* Model to use by the mapper.
*
* @var class-string<T>
* @since 1.0.0
*/
public const MODEL = BaseStringL11nType::class;
/**
* Primary table.
*
* @var string
* @since 1.0.0
*/
public const TABLE = 'billing_payment_term';
/**
* Primary field name.
*
* @var string
* @since 1.0.0
*/
public const PRIMARYFIELD = 'billing_payment_term_id';
}

View File

@ -17,7 +17,7 @@ namespace Modules\Billing\Models;
use phpOMS\Stdlib\Base\Enum;
/**
* Permision state enum.
* Permission category enum.
*
* @package Modules\Billing\Models
* @license OMS License 2.0
@ -35,4 +35,14 @@ abstract class PermissionCategory extends Enum
public const PRIVATE_DASHBOARD = 5;
public const PRIVATE_BILL_UPLOAD = 6;
public const BILL_NOTE = 7;
public const PRICE = 8;
public const PAYMENT_TERM = 9;
public const SHIPPING_TERM = 10;
public const BILL_LOG = 101;
}

View File

@ -32,6 +32,12 @@ use phpOMS\Stdlib\Base\FloatInt;
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @todo Find a way to handle references to the total invoice amount and other items
* Example: If total invoice > $X no shipping expenses
* Maybe additional column referencing total value
* Example: If item Y quantity > Z no costs for item A (e.g. service fee)
* Maybe by referencing another price (i.e. if other price triggered than this is triggered as well)
*/
class Price implements \JsonSerializable
{
@ -49,7 +55,11 @@ class Price implements \JsonSerializable
public Item $item;
public AttributeValue $itemgroup;
public int $status = PriceStatus::ACTIVE;
public AttributeValue $itemsalesgroup;
public AttributeValue $itemproductgroup;
public AttributeValue $itemsegment;
@ -75,20 +85,22 @@ class Price implements \JsonSerializable
public int $type = PriceType::SALES;
public int $quantity = 0;
public FloatInt $quantity;
public FloatInt $price;
public int $priceNew = 0;
public FloatInt $priceNew;
public int $discount = 0;
public FloatInt $discount;
public int $discountPercentage = 0;
public FloatInt $discountPercentage;
public int $bonus = 0;
public FloatInt $bonus;
public bool $multiply = false;
public bool $isAdditive = false;
public string $currency = ISO4217CharEnum::_EUR;
public ?\DateTime $start = null;
@ -102,11 +114,12 @@ class Price implements \JsonSerializable
*/
public function __construct()
{
$this->item = new NullItem();
$this->itemgroup = new NullAttributeValue();
$this->itemsegment = new NullAttributeValue();
$this->itemsection = new NullAttributeValue();
$this->itemtype = new NullAttributeValue();
$this->item = new NullItem();
$this->itemsalesgroup = new NullAttributeValue();
$this->itemproductgroup = new NullAttributeValue();
$this->itemsegment = new NullAttributeValue();
$this->itemsection = new NullAttributeValue();
$this->itemtype = new NullAttributeValue();
$this->client = new NullClient();
$this->clientgroup = new NullAttributeValue();
@ -116,19 +129,12 @@ class Price implements \JsonSerializable
$this->supplier = new NullSupplier();
$this->price = new FloatInt();
}
/**
* Get id.
*
* @return int Model id
*
* @since 1.0.0
*/
public function getId() : int
{
return $this->id;
$this->price = new FloatInt();
$this->quantity = new FloatInt();
$this->priceNew = new FloatInt();
$this->discount = new FloatInt();
$this->discountPercentage = new FloatInt();
$this->bonus = new FloatInt();
}
/**

View File

@ -42,33 +42,35 @@ final class PriceMapper extends DataMapperFactory
* @since 1.0.0
*/
public const COLUMNS = [
'billing_price_id' => ['name' => 'billing_price_id', 'type' => 'int', 'internal' => 'id'],
'billing_price_name' => ['name' => 'billing_price_name', 'type' => 'string', 'internal' => 'name'],
'billing_price_promocode' => ['name' => 'billing_price_promocode', 'type' => 'string', 'internal' => 'promocode'],
'billing_price_item' => ['name' => 'billing_price_item', 'type' => 'int', 'internal' => 'item'],
'billing_price_itemgroup' => ['name' => 'billing_price_itemgroup', 'type' => 'int', 'internal' => 'itemgroup'],
'billing_price_itemsegment' => ['name' => 'billing_price_itemsegment', 'type' => 'int', 'internal' => 'itemsegment'],
'billing_price_itemsection' => ['name' => 'billing_price_itemsection', 'type' => 'int', 'internal' => 'itemsection'],
'billing_price_itemtype' => ['name' => 'billing_price_itemtype', 'type' => 'int', 'internal' => 'itemtype'],
'billing_price_client' => ['name' => 'billing_price_client', 'type' => 'int', 'internal' => 'client'],
'billing_price_clientgroup' => ['name' => 'billing_price_clientgroup', 'type' => 'int', 'internal' => 'clientgroup'],
'billing_price_clientsegment' => ['name' => 'billing_price_clientsegment', 'type' => 'int', 'internal' => 'clientsegment'],
'billing_price_clientsection' => ['name' => 'billing_price_clientsection', 'type' => 'int', 'internal' => 'clientsection'],
'billing_price_clienttype' => ['name' => 'billing_price_clienttype', 'type' => 'int', 'internal' => 'clienttype'],
'billing_price_clientcountry' => ['name' => 'billing_price_clientcountry', 'type' => 'string', 'internal' => 'clientcountry'],
'billing_price_supplier' => ['name' => 'billing_price_supplier', 'type' => 'int', 'internal' => 'supplier'],
'billing_price_unit' => ['name' => 'billing_price_unit', 'type' => 'int', 'internal' => 'unit'],
'billing_price_type' => ['name' => 'billing_price_type', 'type' => 'int', 'internal' => 'type'],
'billing_price_quantity' => ['name' => 'billing_price_quantity', 'type' => 'int', 'internal' => 'quantity'],
'billing_price_price' => ['name' => 'billing_price_price', 'type' => 'Serializable', 'internal' => 'price'],
'billing_price_price_new' => ['name' => 'billing_price_price_new', 'type' => 'int', 'internal' => 'priceNew'],
'billing_price_discount' => ['name' => 'billing_price_discount', 'type' => 'int', 'internal' => 'discount'],
'billing_price_discountp' => ['name' => 'billing_price_discountp', 'type' => 'int', 'internal' => 'discountPercentage'],
'billing_price_bonus' => ['name' => 'billing_price_bonus', 'type' => 'int', 'internal' => 'bonus'],
'billing_price_multiply' => ['name' => 'billing_price_multiply', 'type' => 'bool', 'internal' => 'multiply'],
'billing_price_currency' => ['name' => 'billing_price_currency', 'type' => 'string', 'internal' => 'currency'],
'billing_price_start' => ['name' => 'billing_price_start', 'type' => 'DateTime', 'internal' => 'start'],
'billing_price_end' => ['name' => 'billing_price_end', 'type' => 'DateTime', 'internal' => 'end'],
'billing_price_id' => ['name' => 'billing_price_id', 'type' => 'int', 'internal' => 'id'],
'billing_price_name' => ['name' => 'billing_price_name', 'type' => 'string', 'internal' => 'name'],
'billing_price_promocode' => ['name' => 'billing_price_promocode', 'type' => 'string', 'internal' => 'promocode'],
'billing_price_item' => ['name' => 'billing_price_item', 'type' => 'int', 'internal' => 'item'],
'billing_price_itemsegment' => ['name' => 'billing_price_itemsegment', 'type' => 'int', 'internal' => 'itemsegment'],
'billing_price_itemsection' => ['name' => 'billing_price_itemsection', 'type' => 'int', 'internal' => 'itemsection'],
'billing_price_itemsalesgroup' => ['name' => 'billing_price_itemsalesgroup', 'type' => 'int', 'internal' => 'itemsalesgroup'],
'billing_price_itemproductgroup' => ['name' => 'billing_price_itemproductgroup', 'type' => 'int', 'internal' => 'itemproductgroup'],
'billing_price_itemtype' => ['name' => 'billing_price_itemtype', 'type' => 'int', 'internal' => 'itemtype'],
'billing_price_client' => ['name' => 'billing_price_client', 'type' => 'int', 'internal' => 'client'],
'billing_price_clientsegment' => ['name' => 'billing_price_clientsegment', 'type' => 'int', 'internal' => 'clientsegment'],
'billing_price_clientsection' => ['name' => 'billing_price_clientsection', 'type' => 'int', 'internal' => 'clientsection'],
'billing_price_clientgroup' => ['name' => 'billing_price_clientgroup', 'type' => 'int', 'internal' => 'clientgroup'],
'billing_price_clienttype' => ['name' => 'billing_price_clienttype', 'type' => 'int', 'internal' => 'clienttype'],
'billing_price_clientcountry' => ['name' => 'billing_price_clientcountry', 'type' => 'string', 'internal' => 'clientcountry'],
'billing_price_supplier' => ['name' => 'billing_price_supplier', 'type' => 'int', 'internal' => 'supplier'],
'billing_price_unit' => ['name' => 'billing_price_unit', 'type' => 'int', 'internal' => 'unit'],
'billing_price_type' => ['name' => 'billing_price_type', 'type' => 'int', 'internal' => 'type'],
'billing_price_status' => ['name' => 'billing_price_status', 'type' => 'int', 'internal' => 'status'],
'billing_price_quantity' => ['name' => 'billing_price_quantity', 'type' => 'Serializable', 'internal' => 'quantity'],
'billing_price_price' => ['name' => 'billing_price_price', 'type' => 'Serializable', 'internal' => 'price'],
'billing_price_price_new' => ['name' => 'billing_price_price_new', 'type' => 'Serializable', 'internal' => 'priceNew'],
'billing_price_discount' => ['name' => 'billing_price_discount', 'type' => 'Serializable', 'internal' => 'discount'],
'billing_price_discountp' => ['name' => 'billing_price_discountp', 'type' => 'Serializable', 'internal' => 'discountPercentage'],
'billing_price_bonus' => ['name' => 'billing_price_bonus', 'type' => 'Serializable', 'internal' => 'bonus'],
'billing_price_multiply' => ['name' => 'billing_price_multiply', 'type' => 'bool', 'internal' => 'multiply'],
'billing_price_currency' => ['name' => 'billing_price_currency', 'type' => 'string', 'internal' => 'currency'],
'billing_price_start' => ['name' => 'billing_price_start', 'type' => 'DateTime', 'internal' => 'start'],
'billing_price_end' => ['name' => 'billing_price_end', 'type' => 'DateTime', 'internal' => 'end'],
];
/**
@ -82,9 +84,13 @@ final class PriceMapper extends DataMapperFactory
'mapper' => ItemMapper::class,
'external' => 'billing_price_item',
],
'itemgroup' => [
'itemsalesgroup' => [
'mapper' => ItemAttributeValueMapper::class,
'external' => 'billing_price_itemgroup',
'external' => 'billing_price_itemsalesgroup',
],
'itemproductgroup' => [
'mapper' => ItemAttributeValueMapper::class,
'external' => 'billing_price_itemproductgroup',
],
'itemsegment' => [
'mapper' => ItemAttributeValueMapper::class,
@ -182,7 +188,7 @@ final class PriceMapper extends DataMapperFactory
AND (unit = ? OR unit = null)
*/
// @todo: allow nested where clause (already possible with the query builder, but not with the mappers)
// @todo allow nested where clause (already possible with the query builder, but not with the mappers)
return [];
}

View File

@ -0,0 +1,32 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\Billing\Models\Price
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\Billing\Models\Price;
use phpOMS\Stdlib\Base\Enum;
/**
* Module settings enum.
*
* @package Modules\Billing\Models\Price
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
abstract class PriceStatus extends Enum
{
public const ACTIVE = 1;
public const INACTIVE = 2;
}

View File

@ -42,10 +42,10 @@ final class PurchaseBillMapper extends BillMapper
*/
public static function getPurchaseBeforePivot(
mixed $pivot,
string $column = null,
?string $column = null,
int $limit = 50,
int $depth = 3,
Builder $query = null
?Builder $query = null
) : array
{
return self::getAll()
@ -61,10 +61,10 @@ final class PurchaseBillMapper extends BillMapper
*/
public static function getPurchaseAfterPivot(
mixed $pivot,
string $column = null,
?string $column = null,
int $limit = 50,
int $depth = 3,
Builder $query = null
?Builder $query = null
) : array
{
return self::getAll()
@ -141,7 +141,7 @@ final class PurchaseBillMapper extends BillMapper
*/
public static function getLastOrderDateByItemId(int $id) : ?\DateTimeImmutable
{
// @todo: only delivers/invoice/production (no offers ...)
// @todo only delivers/invoice/production (no offers ...)
$query = new Builder(self::$db);
/** @var false|array $result */
@ -163,7 +163,7 @@ final class PurchaseBillMapper extends BillMapper
*/
public static function getLastOrderDateBySupplierId(int $id) : ?\DateTimeImmutable
{
// @todo: only delivers/invoice/production (no offers ...)
// @todo only delivers/invoice/production (no offers ...)
$query = new Builder(self::$db);
/** @var false|array $result */

View File

@ -39,13 +39,14 @@ final class SalesBillMapper extends BillMapper
/**
* Placeholder
* @todo Implement
*/
public static function getSalesBeforePivot(
mixed $pivot,
string $column = null,
?string $column = null,
int $limit = 50,
int $depth = 3,
Builder $query = null
?Builder $query = null
) : array
{
return self::getAll()
@ -58,13 +59,14 @@ final class SalesBillMapper extends BillMapper
/**
* Placeholder
* @todo Implement
*/
public static function getSalesAfterPivot(
mixed $pivot,
string $column = null,
?string $column = null,
int $limit = 50,
int $depth = 3,
Builder $query = null
?Builder $query = null
) : array
{
return self::getAll()
@ -77,6 +79,7 @@ final class SalesBillMapper extends BillMapper
/**
* Placeholder
* @todo Implement
*/
public static function getSalesByItemId(int $id, \DateTime $start, \DateTime $end) : FloatInt
{
@ -98,6 +101,7 @@ final class SalesBillMapper extends BillMapper
/**
* Placeholder
* @todo Implement
*/
public static function getSalesByClientId(int $id, \DateTime $start, \DateTime $end) : FloatInt
{
@ -117,31 +121,37 @@ final class SalesBillMapper extends BillMapper
/**
* Placeholder
* @todo Implement
*/
public static function getAvgSalesPriceByItemId(int $id, \DateTime $start, \DateTime $end) : FloatInt
public static function getItemAvgSalesPrice(int $item, \DateTime $start, \DateTime $end) : FloatInt
{
$query = new Builder(self::$db);
$sql = <<<SQL
SELECT
SUM(billing_bill_element_single_netsalesprice) as net_sales,
COUNT(billing_bill_element_total_netsalesprice) as net_count
FROM billing_bill_element
JOIN billing_bill ON billing_bill_element.billing_bill_element_bill = billing_bill.billing_bill_id
WHERE
billing_bill_element_item = {$item}
AND billing_bill_performance_date >= '{$start->format('Y-m-d H:i:s')}'
AND billing_bill_performance_date <= '{$end->format('Y-m-d H:i:s')}';
SQL;
/** @var array $result */
$result = $query->select('SUM(billing_bill_element_single_netsalesprice)', 'COUNT(billing_bill_element_total_netsalesprice)')
->from(self::TABLE)
->leftJoin(BillElementMapper::TABLE)
->on(self::TABLE . '.billing_bill_id', '=', BillElementMapper::TABLE . '.billing_bill_element_bill')
->where(BillElementMapper::TABLE . '.billing_bill_element_item', '=', $id)
->andWhere(self::TABLE . '.billing_bill_performance_date', '>=', $start)
->andWhere(self::TABLE . '.billing_bill_performance_date', '<=', $end)
->execute()
?->fetch() ?? [];
$query = new Builder(self::$db);
$result = $query->raw($sql)->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
return new FloatInt(((int) ($result[1] ?? 0)) === 0 ? 0 : (int) (((int) ($result[0] ?? 0)) / ((int) $result[1])));
return isset($result[0]['net_count'])
? new FloatInt((int) ($result[0]['net_sales'] ?? 0) / ($result[0]['net_count']))
: new FloatInt(0);
}
/**
* Placeholder
* @todo Implement
*/
public static function getLastOrderDateByItemId(int $id) : ?\DateTimeImmutable
{
// @todo: only delivers/invoice/production (no offers ...)
// @todo only delivers/invoice/production (no offers ...)
$query = new Builder(self::$db);
/** @var false|array $result */
@ -160,10 +170,11 @@ final class SalesBillMapper extends BillMapper
/**
* Placeholder
* @todo Implement
*/
public static function getLastOrderDateByClientId(int $id) : ?\DateTimeImmutable
{
// @todo: only delivers/invoice/production (no offers ...)
// @todo only delivers/invoice/production (no offers ...)
$query = new Builder(self::$db);
/** @var false|array $result */
@ -180,6 +191,7 @@ final class SalesBillMapper extends BillMapper
/**
* Placeholder
* @todo Implement
*/
public static function getItemRetentionRate(int $id, \DateTime $start, \DateTime $end) : float
{
@ -188,6 +200,7 @@ final class SalesBillMapper extends BillMapper
/**
* Placeholder
* @todo Implement
*/
public static function getItemLivetimeValue(int $id, \DateTime $start, \DateTime $end) : FloatInt
{
@ -196,6 +209,7 @@ final class SalesBillMapper extends BillMapper
/**
* Placeholder
* @todo Implement
*/
public static function getNewestItemInvoices(int $id, int $limit = 10) : array
{
@ -217,6 +231,7 @@ final class SalesBillMapper extends BillMapper
/**
* Placeholder
* @todo Implement
*/
public static function getNewestClientInvoices(int $id, int $limit = 10) : array
{
@ -236,6 +251,7 @@ final class SalesBillMapper extends BillMapper
/**
* Placeholder
* @todo Implement
*/
public static function getItemTopClients(int $id, \DateTime $start, \DateTime $end, int $limit = 10) : array
{
@ -276,14 +292,19 @@ final class SalesBillMapper extends BillMapper
/**
* Placeholder
* @todo Implement
*/
public static function getItemBills(int $id, \DateTime $start, \DateTime $end) : array
{
$query = self::getQuery();
$query = self::reader()
->with('type')
->with('type/l11n')
->where('type/l11n/language', 'en')
->getQuery();
$query->leftJoin(BillElementMapper::TABLE, BillElementMapper::TABLE . '_d1')
->on(self::TABLE . '_d1.billing_bill_id', '=', BillElementMapper::TABLE . '_d1.billing_bill_element_bill')
->where(BillElementMapper::TABLE . '_d1.billing_bill_element_item', '=', $id)
->limit($limit = 10);
->where(BillElementMapper::TABLE . '_d1.billing_bill_element_item', '=', $id);
/** @phpstan-ignore-next-line */
if (!empty(self::CREATED_AT)) {
@ -292,32 +313,45 @@ final class SalesBillMapper extends BillMapper
$query->orderBy(self::TABLE . '_d1.' . self::COLUMNS[self::PRIMARYFIELD]['name'], 'DESC');
}
return self::getAll()->execute($query);
return self::getAll()
->with('type')
->with('type/l11n')
->execute($query);
}
/**
* Placeholder
* @todo Implement
*/
public static function getClientBills(int $id, string $language, \DateTime $start, \DateTime $end) : array
{
return self::getAll()
->with('type')
->with('type/l11n')
->where('client', $id)
->where('type/l11n/language', $language)
->where('billDate', $start, '>=')
->where('billDate', $end, '<=')
->execute();
}
/**
* Placeholder
* @todo Implement
*/
public static function getClientItem(int $client, \DateTime $start, \DateTime $end) : array
{
$query = BillElementMapper::getQuery();
$query->leftJoin(self::TABLE, self::TABLE . '_d1')
->on(BillElementMapper::TABLE . '_d1.billing_bill_element_bill', '=', self::TABLE . '_d1.billing_bill_id')
->where(self::TABLE . '_d1.billing_bill_client', '=', $client)
->limit($limit = 10);
/** @phpstan-ignore-next-line */
if (!empty(self::CREATED_AT)) {
$query->orderBy(self::TABLE . '_d1.' . self::COLUMNS[self::CREATED_AT]['name'], 'DESC');
} else {
$query->orderBy(self::TABLE . '_d1.' . self::COLUMNS[self::PRIMARYFIELD]['name'], 'DESC');
}
return BillElementMapper::getAll()->execute($query);
return BillElementMapper::getAll()
->with('bill')
->with('bill/type')
->where('bill/client', $client)
->where('bill/type/transferStock', true)
->execute();
}
/**
* Placeholder
* @todo Implement
*/
public static function getItemCountrySales(int $id, \DateTime $start, \DateTime $end, int $limit = 10) : array
{
@ -343,47 +377,240 @@ final class SalesBillMapper extends BillMapper
/**
* Placeholder
* @todo Implement
*/
public static function getItemMonthlySalesCosts(int $id, \DateTime $start, \DateTime $end) : array
public static function getItemMonthlySalesCosts(array $items, \DateTime $start, \DateTime $end) : array
{
if (empty($items)) {
return [];
}
$item = \implode(',', $items);
$sql = <<<SQL
SELECT
billing_bill_element_item,
SUM(billing_bill_element_total_netsalesprice) as net_sales,
SUM(billing_bill_element_total_netpurchaseprice) as net_costs,
YEAR(billing_bill_performance_date) as year,
MONTH(billing_bill_performance_date) as month
FROM billing_bill_element
JOIN billing_bill ON billing_bill_element.billing_bill_element_bill = billing_bill.billing_bill_id
WHERE
billing_bill_element_item IN ({$item})
AND billing_bill_performance_date >= '{$start->format('Y-m-d H:i:s')}'
AND billing_bill_performance_date <= '{$end->format('Y-m-d H:i:s')}'
GROUP BY billing_bill_element_item, year, month
ORDER BY billing_bill_element_item, year ASC, month ASC;
SQL;
$query = new Builder(self::$db);
$result = $query->selectAs('SUM(billing_bill_element_total_netsalesprice)', 'net_sales')
->selectAs('SUM(billing_bill_element_total_netpurchaseprice)', 'net_costs')
->selectAs('YEAR(billing_bill_performance_date)', 'year')
->selectAs('MONTH(billing_bill_performance_date)', 'month')
->from(self::TABLE)
->leftJoin(BillElementMapper::TABLE)
->on(self::TABLE . '.billing_bill_id', '=', BillElementMapper::TABLE . '.billing_bill_element_bill')
->where(BillElementMapper::TABLE . '.billing_bill_element_item', '=', $id)
->andWhere(self::TABLE . '.billing_bill_performance_date', '>=', $start)
->andWhere(self::TABLE . '.billing_bill_performance_date', '<=', $end)
->groupBy('year', 'month')
->orderBy(['year', 'month'], ['ASC', 'ASC'])
->execute()
?->fetchAll();
$result = $query->raw($sql)->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
return $result ?? [];
}
/**
* Placeholder
* @todo Implement
*/
public static function getClientMonthlySalesCosts(int $id, \DateTime $start, \DateTime $end) : array
public static function getItemMonthlySalesQuantity(array $items, \DateTime $start, \DateTime $end) : array
{
if (empty($items)) {
return [];
}
$item = \implode(',', $items);
$sql = <<<SQL
SELECT
billing_bill_element_item as item,
SUM(billing_bill_element_quantity) as quantity,
YEAR(billing_bill_performance_date) as year,
MONTH(billing_bill_performance_date) as month
FROM billing_bill_element
JOIN billing_bill ON billing_bill_element.billing_bill_element_bill = billing_bill.billing_bill_id
WHERE
billing_bill_element_item IN ({$item})
AND billing_bill_performance_date >= '{$start->format('Y-m-d H:i:s')}'
AND billing_bill_performance_date <= '{$end->format('Y-m-d H:i:s')}'
GROUP BY item, year, month
ORDER BY item, year ASC, month ASC;
SQL;
$query = new Builder(self::$db);
$result = $query->selectAs('SUM(billing_bill_netsales)', 'net_sales')
->selectAs('SUM(billing_bill_netcosts)', 'net_costs')
->selectAs('YEAR(billing_bill_performance_date)', 'year')
->selectAs('MONTH(billing_bill_performance_date)', 'month')
->from(self::TABLE)
->where(self::TABLE . '.billing_bill_client', '=', $id)
->andWhere(self::TABLE . '.billing_bill_performance_date', '>=', $start)
->andWhere(self::TABLE . '.billing_bill_performance_date', '<=', $end)
->groupBy('year', 'month')
->orderBy(['year', 'month'], ['ASC', 'ASC'])
->execute()
?->fetchAll();
$result = $query->raw($sql)->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
return $result ?? [];
}
/**
* Placeholder
* @todo Implement
*/
public static function getClientMonthlySalesCosts(int $client, \DateTime $start, \DateTime $end) : array
{
$sql = <<<SQL
SELECT
SUM(billing_bill_netsales) as net_sales,
SUM(billing_bill_netcosts) as net_costs,
YEAR(billing_bill_performance_date) as year,
MONTH(billing_bill_performance_date) as month
FROM billing_bill
WHERE
billing_bill_client = {$client}
AND billing_bill_performance_date >= '{$start->format('Y-m-d H:i:s')}'
AND billing_bill_performance_date <= '{$end->format('Y-m-d H:i:s')}'
GROUP BY year, month
ORDER BY year ASC, month ASC;
SQL;
$query = new Builder(self::$db);
$result = $query->raw($sql)->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
return $result ?? [];
}
/**
* Placeholder
* @todo Implement
*/
public static function getItemNetSales(int $item, \DateTime $start, \DateTime $end) : FloatInt
{
$sql = <<<SQL
SELECT SUM(billing_bill_element_single_netsalesprice) as net_sales
FROM billing_bill_element
JOIN billing_bill ON billing_bill_element.billing_bill_element_bill = billing_bill.billing_bill_id
WHERE
billing_bill_element_item = {$item}
AND billing_bill_performance_date >= '{$start->format('Y-m-d H:i:s')}'
AND billing_bill_performance_date <= '{$end->format('Y-m-d H:i:s')}';
SQL;
$query = new Builder(self::$db);
$result = $query->raw($sql)->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
return new FloatInt((int) ($result[0]['net_sales'] ?? 0));
}
/**
* Placeholder
* @todo Implement
*/
public static function getILVHistoric(int $item) : FloatInt
{
$sql = <<<SQL
SELECT SUM(billing_bill_element_single_netsalesprice) as net_sales
FROM billing_bill_element
JOIN billing_bill ON billing_bill_element.billing_bill_element_bill = billing_bill.billing_bill_id
WHERE billing_bill_element_item = {$item}
SQL;
$query = new Builder(self::$db);
$result = $query->raw($sql)->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
return new FloatInt((int) ($result[0]['net_sales'] ?? 0));
}
/**
* Placeholder
* @todo Implement
*/
public static function getItemMRR() : FloatInt
{
return new FloatInt(0);
}
/**
* Placeholder
* @todo Implement
*/
public static function getItemLastOrder(int $item) : ?\DateTime
{
$sql = <<<SQL
SELECT billing_bill_created_at
FROM billing_bill
JOIN billing_bill_element ON billing_bill.billing_bill_id = billing_bill_element.billing_bill_element_id
WHERE billing_bill_element_item = {$item}
ORDER BY billing_bill_created_at DESC
LIMIT 1;
SQL;
$query = new Builder(self::$db);
$result = $query->raw($sql)->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
return isset($result[0]['billing_bill_created_at'])
? new \DateTime(($result[0]['billing_bill_created_at']))
: null;
}
/**
* Placeholder
* @todo Implement
*/
public static function getClientNetSales(int $client, \DateTime $start, \DateTime $end) : FloatInt
{
$sql = <<<SQL
SELECT SUM(billing_bill_netsales) as net_sales
FROM billing_bill
WHERE
billing_bill_client = {$client}
AND billing_bill_performance_date >= '{$start->format('Y-m-d H:i:s')}'
AND billing_bill_performance_date <= '{$end->format('Y-m-d H:i:s')}';
SQL;
$query = new Builder(self::$db);
$result = $query->raw($sql)->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
return new FloatInt((int) ($result[0]['net_sales'] ?? 0));
}
/**
* Placeholder
* @todo Implement
*/
public static function getCLVHistoric(int $client) : FloatInt
{
$sql = <<<SQL
SELECT SUM(billing_bill_netsales) as net_sales
FROM billing_bill
WHERE billing_bill_client = {$client};
SQL;
$query = new Builder(self::$db);
$result = $query->raw($sql)->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
return new FloatInt((int) ($result[0]['net_sales'] ?? 0));
}
/**
* Placeholder
* @todo Implement
*/
public static function getClientMRR() : FloatInt
{
return new FloatInt(0);
}
/**
* Placeholder
* @todo Implement
*/
public static function getClientLastOrder(int $client) : ?\DateTime
{
$sql = <<<SQL
SELECT billing_bill_created_at
FROM billing_bill
WHERE billing_bill_client = {$client}
ORDER BY billing_bill_created_at DESC
LIMIT 1;
SQL;
$query = new Builder(self::$db);
$result = $query->raw($sql)->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
return isset($result[0]['billing_bill_created_at'])
? new \DateTime(($result[0]['billing_bill_created_at']))
: null;
}
}

View File

@ -28,9 +28,13 @@ abstract class SettingsEnum extends Enum
{
public const PREVIEW_MEDIA_TYPE = '1005100001'; // internally generated preview
public const ORIGINAL_MEDIA_TYPE = '1005100002'; // original document (client = invoice sent to client, supplier = invoice from supplier)
public const INTERNAL_MEDIA_TYPE = '1005100002'; // original document (client = invoice sent to client, supplier = invoice from supplier)
public const EXTERNAL_MEDIA_TYPE = '1005100006'; // original document (client = invoice sent to client, supplier = invoice from supplier)
public const VALID_BILL_LANGUAGES = '1005100003'; // List of valid languages for bills
public const BILLING_CUSTOMER_EMAIL_TEMPLATE = '1005100004'; // Email template for customer billing
public const BILLING_SUPPLIER_EMAIL_TEMPLATE = '1005100005'; // Email template for supplier billing
}

View File

@ -0,0 +1,69 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\Billing\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\Billing\Models;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
use phpOMS\Localization\BaseStringL11n;
/**
* Item mapper class.
*
* @package Modules\Billing\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @template T of BaseStringL11n
* @extends DataMapperFactory<T>
*/
final class ShippingTermL11nMapper extends DataMapperFactory
{
/**
* Columns.
*
* @var array<string, array{name:string, type:string, internal:string, autocomplete?:bool, readonly?:bool, writeonly?:bool, annotations?:array}>
* @since 1.0.0
*/
public const COLUMNS = [
'billing_shipping_term_l11n_id' => ['name' => 'billing_shipping_term_l11n_id', 'type' => 'int', 'internal' => 'id'],
'billing_shipping_term_l11n_name' => ['name' => 'billing_shipping_term_l11n_name', 'type' => 'string', 'internal' => 'content', 'autocomplete' => true],
'billing_shipping_term_l11n_term' => ['name' => 'billing_shipping_term_l11n_term', 'type' => 'int', 'internal' => 'ref'],
'billing_shipping_term_l11n_language' => ['name' => 'billing_shipping_term_l11n_language', 'type' => 'string', 'internal' => 'language'],
];
/**
* Primary table.
*
* @var string
* @since 1.0.0
*/
public const TABLE = 'billing_shipping_term_l11n';
/**
* Primary field name.
*
* @var string
* @since 1.0.0
*/
public const PRIMARYFIELD = 'billing_shipping_term_l11n_id';
/**
* Model to use by the mapper.
*
* @var class-string<T>
* @since 1.0.0
*/
public const MODEL = BaseStringL11n::class;
}

View File

@ -0,0 +1,83 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\Billing\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\Billing\Models;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
use phpOMS\Localization\BaseStringL11nType;
/**
* Item mapper class.
*
* @package Modules\Billing\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @template T of BaseStringL11nType
* @extends DataMapperFactory<T>
*/
final class ShippingTermMapper extends DataMapperFactory
{
/**
* Columns.
*
* @var array<string, array{name:string, type:string, internal:string, autocomplete?:bool, readonly?:bool, writeonly?:bool, annotations?:array}>
* @since 1.0.0
*/
public const COLUMNS = [
'billing_shipping_term_id' => ['name' => 'billing_shipping_term_id', 'type' => 'int', 'internal' => 'id'],
'billing_shipping_term_code' => ['name' => 'billing_shipping_term_code', 'type' => 'string', 'internal' => 'title', 'autocomplete' => true],
];
/**
* Has many relation.
*
* @var array<string, array{mapper:class-string, table:string, self?:?string, external?:?string, column?:string}>
* @since 1.0.0
*/
public const HAS_MANY = [
'l11n' => [
'mapper' => ShippingTermL11nMapper::class,
'table' => 'billing_shipping_term_l11n',
'self' => 'billing_shipping_term_l11n_term',
'column' => 'content',
'external' => null,
],
];
/**
* Model to use by the mapper.
*
* @var class-string<T>
* @since 1.0.0
*/
public const MODEL = BaseStringL11nType::class;
/**
* Primary table.
*
* @var string
* @since 1.0.0
*/
public const TABLE = 'billing_shipping_term';
/**
* Primary field name.
*
* @var string
* @since 1.0.0
*/
public const PRIMARYFIELD = 'billing_shipping_term_id';
}

View File

@ -39,10 +39,10 @@ final class StockBillMapper extends BillMapper
*/
public static function getStockBeforePivot(
mixed $pivot,
string $column = null,
?string $column = null,
int $limit = 50,
int $depth = 3,
Builder $query = null
?Builder $query = null
) : array
{
return self::getAll()
@ -58,10 +58,10 @@ final class StockBillMapper extends BillMapper
*/
public static function getStockAfterPivot(
mixed $pivot,
string $column = null,
?string $column = null,
int $limit = 50,
int $depth = 3,
Builder $query = null
?Builder $query = null
) : array
{
return self::getAll()

View File

@ -50,7 +50,7 @@ class Subscription implements \JsonSerializable
public int $client = 0;
public int $quantity = 0;
public FloatInt $quantity;
/**
* Constructor.
@ -59,19 +59,8 @@ class Subscription implements \JsonSerializable
*/
public function __construct()
{
$price = new FloatInt();
}
/**
* Get id.
*
* @return int Model id
*
* @since 1.0.0
*/
public function getId() : int
{
return $this->id;
$price = new FloatInt();
$quantity = new FloatInt();
}
/**
@ -80,7 +69,7 @@ class Subscription implements \JsonSerializable
public function toArray() : array
{
return [
'id' => $this->id,
'id' => $this->id,
];
}

View File

@ -41,7 +41,7 @@ final class SubscriptionMapper extends DataMapperFactory
'billing_subscription_start' => ['name' => 'billing_subscription_start', 'type' => 'DateTime', 'internal' => 'start'],
'billing_subscription_end' => ['name' => 'billing_subscription_end', 'type' => 'DateTime', 'internal' => 'end'],
'billing_subscription_price' => ['name' => 'billing_subscription_price', 'type' => 'Serializable', 'internal' => 'price'],
'billing_subscription_quantity' => ['name' => 'billing_subscription_quantity', 'type' => 'int', 'internal' => 'quantity'],
'billing_subscription_quantity' => ['name' => 'billing_subscription_quantity', 'type' => 'Serializable', 'internal' => 'quantity'],
'billing_subscription_bill' => ['name' => 'billing_subscription_bill', 'type' => 'int', 'internal' => 'bill'],
'billing_subscription_item' => ['name' => 'billing_subscription_item', 'type' => 'int', 'internal' => 'item'],
'billing_subscription_autorenew' => ['name' => 'billing_subscription_autorenew', 'type' => 'bool', 'internal' => 'autoRenew'],

View File

@ -34,6 +34,7 @@ final class NullTaxCombination extends TaxCombination
public function __construct(int $id = 0)
{
$this->id = $id;
parent::__construct();
}
/**

View File

@ -16,6 +16,8 @@ namespace Modules\Billing\Models\Tax;
use Modules\Attribute\Models\AttributeValue;
use Modules\Attribute\Models\NullAttributeValue;
use Modules\Finance\Models\NullTaxCode;
use Modules\Finance\Models\TaxCode;
/**
* Billing class.
@ -41,18 +43,30 @@ class TaxCombination implements \JsonSerializable
public AttributeValue $itemCode;
public string $taxCode = '';
// @todo: consider to add the tax code object directly, it is annoying to make a manuall mapper call which is often required afterwards.
public TaxCode $taxCode;
public int $taxType = BillTaxType::SALES;
public string $account = '';
// Tax accounts can be defined in:
// 1. Account (gross postings are automatically split)
// 2. Tax code
// 3. Tax combination
public string $taxAccount1 = '';
public string $taxAccount2 = '';
public string $refundAccount = '';
public string $discountAccount = '';
public string $cashbackAccount = '';
public string $overpaymentAccount = '';
public string $underpaymentAccount = '';
public ?int $minPrice = null;
public ?int $maxPrice = null;
@ -69,6 +83,7 @@ class TaxCombination implements \JsonSerializable
public function __construct()
{
$this->itemCode = new NullAttributeValue();
$this->taxCode = new NullTaxCode();
}
/**
@ -77,7 +92,7 @@ class TaxCombination implements \JsonSerializable
public function toArray() : array
{
return [
'id' => $this->id,
'id' => $this->id,
];
}

View File

@ -15,8 +15,9 @@ declare(strict_types=1);
namespace Modules\Billing\Models\Tax;
use Modules\ClientManagement\Models\Attribute\ClientAttributeValueMapper;
use Modules\Finance\Models\TaxCodeMapper;
use Modules\ItemManagement\Models\Attribute\ItemAttributeValueMapper;
use Modules\SupplierManagement\Models\SupplierAttributeValueMapper;
use Modules\SupplierManagement\Models\Attribute\SupplierAttributeValueMapper;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
/**
@ -39,19 +40,24 @@ final class TaxCombinationMapper extends DataMapperFactory
* @since 1.0.0
*/
public const COLUMNS = [
'billing_tax_id' => ['name' => 'billing_tax_id', 'type' => 'int', 'internal' => 'id'],
'billing_tax_client_code' => ['name' => 'billing_tax_client_code', 'type' => 'int', 'internal' => 'clientCode'],
'billing_tax_supplier_code' => ['name' => 'billing_tax_supplier_code', 'type' => 'int', 'internal' => 'supplierCode'],
'billing_tax_item_code' => ['name' => 'billing_tax_item_code', 'type' => 'int', 'internal' => 'itemCode'],
'billing_tax_code' => ['name' => 'billing_tax_code', 'type' => 'string', 'internal' => 'taxCode'],
'billing_tax_type' => ['name' => 'billing_tax_type', 'type' => 'int', 'internal' => 'taxType'],
'billing_tax_account' => ['name' => 'billing_tax_account', 'type' => 'string', 'internal' => 'account'],
'billing_tax_refund_account' => ['name' => 'billing_tax_refund_account', 'type' => 'string', 'internal' => 'refundAccount'],
'billing_tax_discount_account' => ['name' => 'billing_tax_discount_account', 'type' => 'string', 'internal' => 'discountAccount'],
'billing_tax_min_price' => ['name' => 'billing_tax_min_price', 'type' => 'int', 'internal' => 'minPrice'],
'billing_tax_max_price' => ['name' => 'billing_tax_max_price', 'type' => 'int', 'internal' => 'maxPrice'],
'billing_tax_start' => ['name' => 'billing_tax_start', 'type' => 'DateTime', 'internal' => 'start'],
'billing_tax_end' => ['name' => 'billing_tax_end', 'type' => 'DateTime', 'internal' => 'end'],
'billing_tax_id' => ['name' => 'billing_tax_id', 'type' => 'int', 'internal' => 'id'],
'billing_tax_client_code' => ['name' => 'billing_tax_client_code', 'type' => 'int', 'internal' => 'clientCode'],
'billing_tax_supplier_code' => ['name' => 'billing_tax_supplier_code', 'type' => 'int', 'internal' => 'supplierCode'],
'billing_tax_item_code' => ['name' => 'billing_tax_item_code', 'type' => 'int', 'internal' => 'itemCode'],
'billing_tax_code' => ['name' => 'billing_tax_code', 'type' => 'string', 'internal' => 'taxCode'],
'billing_tax_type' => ['name' => 'billing_tax_type', 'type' => 'int', 'internal' => 'taxType'],
'billing_tax_account' => ['name' => 'billing_tax_account', 'type' => 'string', 'internal' => 'account'],
'billing_tax_tax1_account' => ['name' => 'billing_tax_tax1_account', 'type' => 'string', 'internal' => 'taxAccount1'],
'billing_tax_tax2_account' => ['name' => 'billing_tax_tax2_account', 'type' => 'string', 'internal' => 'taxAccount2'],
'billing_tax_refund_account' => ['name' => 'billing_tax_refund_account', 'type' => 'string', 'internal' => 'refundAccount'],
'billing_tax_discount_account' => ['name' => 'billing_tax_discount_account', 'type' => 'string', 'internal' => 'discountAccount'],
'billing_tax_cashback_account' => ['name' => 'billing_tax_cashback_account', 'type' => 'string', 'internal' => 'cashbackAccount'],
'billing_tax_overpayment_account' => ['name' => 'billing_tax_overpayment_account', 'type' => 'string', 'internal' => 'overpaymentAccount'],
'billing_tax_underpayment_account' => ['name' => 'billing_tax_underpayment_account', 'type' => 'string', 'internal' => 'underpaymentAccount'],
'billing_tax_min_price' => ['name' => 'billing_tax_min_price', 'type' => 'int', 'internal' => 'minPrice'],
'billing_tax_max_price' => ['name' => 'billing_tax_max_price', 'type' => 'int', 'internal' => 'maxPrice'],
'billing_tax_start' => ['name' => 'billing_tax_start', 'type' => 'DateTime', 'internal' => 'start'],
'billing_tax_end' => ['name' => 'billing_tax_end', 'type' => 'DateTime', 'internal' => 'end'],
];
/**
@ -73,6 +79,11 @@ final class TaxCombinationMapper extends DataMapperFactory
'mapper' => ItemAttributeValueMapper::class,
'external' => 'billing_tax_item_code',
],
'taxCode' => [
'mapper' => TaxCodeMapper::class,
'external' => 'billing_tax_code',
'by' => 'abbr',
],
];
/**

View File

@ -1,106 +0,0 @@
{
"type": {
"purchase_invoice": {
"en": [
"Invoice"
],
"de": [
"Rechnung"
]
},
"purchase_credit_note": {
"en": [
"Credit Note"
],
"de": [
"Rechnungskorrektur",
"Gutschrift"
]
},
"purchase_delivery_note": {
"en": [
"Delivery Note"
],
"de": [
"Lieferschein"
]
},
"purchase_order_confirmation": {
"en": [
"Order Confirmation"
],
"de": [
"Auftragsbestätigung"
]
},
"purchase_reverse_invoice": {
"en": [
"Credit Note"
],
"de": [
"Gutschrift"
]
}
},
"date_format": [
"Y-m-d",
"Y.m.d",
"Y/m/d",
"d-m-Y",
"d.m.Y",
"d/m/Y",
"m-d-Y",
"m.d.Y",
"m/d/Y",
"M. d.Y",
"M. d. Y",
"M. d Y",
"M. d,Y",
"M. d, Y",
"M d.Y",
"M d. Y",
"M d Y",
"M d,Y",
"M d, Y",
"M, d.Y",
"M, d. Y",
"M, d Y",
"M, d,Y",
"M, d, Y"
],
"bill_no": {
"en": [
"/(inv.*?)(no|\\s|,|:|\\.|#)+(?<bill_no>.*?)( |$)/i",
"/(#)(?<bill_no>.*?)( |$)/i"
],
"de": [
"/(rechnungsn.*?|beleg.*?)(?<bill_no>.*?)( |$)/i"
]
},
"bill_date": {
"en": [
"/(inv.*?)(date.*?)(\\s|,|:|\\.)+(?<bill_date>.*?)( |$)/i",
"/(date.*?)(\\s|,|:|\\.)+(?<bill_date>.*?)( |$)/i"
],
"de": [
"/(rechnungsdat.*?|belegdat.*?)(\\s|,|:|\\.)+(?<bill_date>.*?)( |$)/i"
]
},
"bill_due": {
"en": [
"/(due date.*?)(\\s|,|:|\\.)+(?<bill_due>.*?)( |$)/i",
"/(due.*?)(\\s|,|:|\\.)+(?<bill_due>.*?)( |$)/i"
],
"de": [
"/(fällig.*?)(\\s|,|:|\\.)+(?<bill_due>.*?)( |$)/i"
]
},
"total_gross": {
"en": [
"/(total.*?|gross.*?)(?<total_gross>([0-9]+,*\\.*)+)/i"
],
"de": [
"/(betrag.*?|gesamt.*?|brutto.*?)(?<total_gross>([0-9]+,*\\.*)+)/i"
]
}
}

251
Models/bill_identifier.json Normal file
View File

@ -0,0 +1,251 @@
{
"type": {
"purchase_invoice": {
"en": [
"Invoice",
"Receipt"
],
"de": [
"Rechnung",
"Quittung"
]
},
"purchase_credit_note": {
"en": [
"Credit Note"
],
"de": [
"Rechnungskorrektur",
"Gutschrift"
]
},
"purchase_delivery_note": {
"en": [
"Delivery Note"
],
"de": [
"Lieferschein"
]
},
"purchase_order_confirmation": {
"en": [
"Order Confirmation"
],
"de": [
"Auftragsbestätigung"
]
},
"purchase_offer": {
"en": [
"Offer"
],
"de": [
"Angebot"
]
},
"purchase_reverse_invoice": {
"en": [],
"de": [
"Gutschrift"
]
},
"purchase_proforma_invoice": {
"en": [
"Proforma"
],
"de": [
"Proforma"
]
}
},
"tax_id": {
"en": [
"/(tax[\\. \\-]*id|tin|ssn|ein)(.*? {1,})(?<tax_id>(.{6,15}))( |$)/i",
"/(vat[\\. \\-]*id)(.*? {1,})(?<tax_id>([^a-zA-Z]{6,15}))( |$)/i"
],
"de": [
"/(Steuern|Steuer[\\. \\-]*Nr|St[\\. \\-]*Nr)(.*? {1,})(?<tax_id>(.{8,15}))( |$)/i",
"/(USt[\\. \\-]*Id|Umsatzst.*?Id)(.*? {1,})(?<tax_id>([^a-zA-Z]{8,15}))( |$)/i"
]
},
"vat_id": {
"en": [
"/(vat[\\. \\-]*id)(.*? {1,})(?<vat_id>([a-zA-Z]{2})(.*?){7,13})( |$)/i"
],
"de": [
"/(USt[\\. \\-]*Id|Umsatzst.*?Id)(.*? {1,})(?<vat_id>([a-zA-Z]{2})(.*?){7,13})( |$)/i"
]
},
"iban": ["/(IBAN)(.*? {1,})(?<iban>([a-zA-Z]{2,}[ 0-9]{14,}))( |$)/i"],
"email": ["/(^| )(?<email>([a-zA-Z0-9\\-]+@[a-zA-Z0-9\\-]+\\.[a-zA-Z]{2,}))( |$)/i"],
"website": ["/(^| )(?<website>(https:\\/\\/|www\\.)([a-zA-Z0-9\\-]+\\.[a-zA-Z]{2,}))( |$)/i"],
"phone": {
"en": [
"/(phone)(.*? {1,})(?<phone>([+0-9 \\/\\-\\(\\)]*[0-9]+[+0-9 \\/\\-\\(\\)]*){4,})( |[^ 0-9\\/\\(\\)+\\-]|$)/i"
],
"de": [
"/(Tel|Rufn)(.*? {1,})(?<phone>([+0-9 \\/\\-\\(\\)]*[0-9]+[+0-9 \\/\\-\\(\\)]*){4,})( |[^ 0-9\\/\\(\\)+\\-]|$)/i"
]
},
"date_format": [
"Y-m-d", "Y.m.d", "Y/m/d",
"d-m-Y", "d.m.Y", "d/m/Y",
"m-d-Y", "m.d.Y", "m/d/Y",
"M. d.Y", "M. d. Y", "M. d Y",
"M. d,Y", "M. d, Y", "M d.Y",
"M d. Y", "M d Y", "M d,Y",
"M d, Y", "M, d.Y", "M, d. Y",
"M, d Y", "M, d,Y", "M, d, Y",
"d-m-y", "d.m.y", "d/m/y",
"m-d-y", "m.d.y", "m/d/y"
],
"bill_no": {
"en": [
"/(invoice|inv.*? no)(.*? {1,})(?<bill_no>\\S*?)( |$)/i",
"/(#)(?<bill_no>\\S*?)( |$)/i"
],
"de": [
"/(rechnungsn|rechnung n|belegn|beleg n)(.*? {1,})(?<bill_no>\\S*?)( |$)/i"
]
},
"bill_date": {
"en": [
"/(inv.*? )(date.*? )(?<bill_date>.{8,}?)( |$)/i",
"/(date.*? )(?<bill_date>.{8,}?)( |$)/i"
],
"de": [
"/(rechnungsdat|belegdat|datum)(.*? )(?<bill_date>\\S{8,}?)( |$)/i"
]
},
"bill_due": {
"en": [
"/(due date.*? )(?<bill_due>\\S{8,}?)( |$)/i",
"/(due.*? )(?<bill_due>\\S{8,}?)( |$)/i"
],
"de": [
"/(fällig.*? )(?<bill_due>\\S{8,}?)( |$)/i"
]
},
"total_net": {
"en": [
"/(subtotal|net)(.*? {1,})(?<total_net>([0-9]+,*\\.*)+)(?! *%)/i"
],
"de": [
"/(netto|zwischensumme|betrag exk)(.*? {1,})(?<total_net>([0-9]+,*\\.*)+)(?! *%)/i"
]
},
"total_discount": {
"en": [
"/(discount)(.*? {1,})(?<total_discount>([0-9]+,*\\.*)+)(?! *%)/i"
],
"de": [
"/(rabatt)(.*? {1,})(?<total_discount>([0-9]+,*\\.*)+)(?! *%)/i"
]
},
"total_shipping": {
"en": [
"/(fuel|handling|fright|shipping)(.*? {1,})(?<total_shipping>([0-9]+,*\\.*)+)(?! *%)/i"
],
"de": [
"/(versand|transport|fracht)(.*? {1,})(?<total_shipping>([0-9]+,*\\.*)+)(?! *%)/i"
]
},
"total_customs": {
"en": [
"/(customs)(.*? {1,})(?<total_customs>([0-9]+,*\\.*)+)(?! *%)/i"
],
"de": [
"/(Einfuhr)(\\S* )(?<total_customs>([0-9]+,*\\.*)+)(?! *%)/i"
]
},
"total_insurance": {
"en": [
"/(insurance)(.*? {1,})(?<total_insurance>([0-9]+,*\\.*)+)(?! *%)/i"
],
"de": [
"/(versicherung)(.*? {1,})(?<total_insurance>([0-9]+,*\\.*)+)(?! *%)/i"
]
},
"total_surcharge": {
"en": [
"/(fee|surcharge)(.*? {1,})(?<total_surcharge>([0-9]+,*\\.*)+)(?! *%)/i"
],
"de": [
"/(gebühr)(.*? {1,})(?<total_surcharge>([0-9]+,*\\.*)+)(?! *%)/i"
]
},
"total_tax": {
"en": [
"/(VAT|tax)(.*? {1,})(?<total_tax>([0-9]+,*\\.*)+)(?! *%)/i"
],
"de": [
"/(USt|Mwst|Umsatzst|Mehrwertst)(.*? {1,})(?<total_tax>([0-9]+,*\\.*)+)(?! *%)/i",
"/( {1,})(USt|Mwst|Umsatzst|Mehrwertst)(?<total_tax>([0-9]+,*\\.*)+)(?! *%)/i"
]
},
"tax_rate": {
"en": [
"/(VAT|tax)(.*? {1,})(?<tax_rate>([0-9]+,*\\.*)+)(?= *%)/i"
],
"de": [
"/(USt|Mwst|Umsatzst|Mehrwertst)(.*? {1,})(?<tax_rate>([0-9]+,*\\.*)+)(?= *%)/i",
"/( {1,})(?<tax_rate>([0-9]+,*\\.*)+)(?= *%)(.*?)(USt|Mwst|Umsatzst|Mehrwertst)/i"
]
},
"total_gross": {
"en": [
"/(total|gross)(.*? {1,})(?<total_gross>([0-9]+,*\\.*)+)(?! *%)/i"
],
"de": [
"/(betrag|gesamt|brutto|summe)(.*? {1,})(?<total_gross>([0-9]+,*\\.*)+)(?! *%)/i"
]
},
"item_table": {
"en": {
"headline": {
"order": ["no.", "#", "pos"],
"number": ["number"],
"description": ["description", "name", "service", "product", "item"],
"quantity": ["qty", "quantity", "hours"],
"price": ["price", "rate"],
"unit": ["unit"],
"total": ["amount", "total", "gross"],
"tax": ["tax"]
},
"parts": "/( *)(.+?)(\\s{3,}|$)/i",
"row": {
"order": "/\\d+/i",
"number": "/.*/i",
"description": "/.*/i",
"quantity": "/[+-]?([0-9]+,*\\.*)+/i",
"price": "/[+-]?([0-9]+,*\\.*)+/i",
"unit": "/.*/i",
"total": "/[+-]?([0-9]+,*\\.*)+/i",
"tax": "/[+-]?([0-9]+,*\\.*)+/i"
}
},
"de": {
"headline": {
"order": ["Pos", "#", "Position"],
"number": ["Nr.", "Nummer"],
"description": ["Beschreibung", "Bez", "Bezeichnung", "Leistung", "Produkt", "Artikel", "Name"],
"quantity": ["Menge", "Anzahl", "Stunden"],
"price": ["Einzel", "Preis", "Preis pro"],
"unit": ["Einheit", "Einh"],
"total": ["Gesamt", "Brutto", "Summe"],
"tax": ["MwSt", "USt", "Steuer"]
},
"parts": "/( *)(.+?)(\\s{2,}|$)/i",
"row": {
"order": "/\\d+/i",
"number": "/.*/i",
"description": "/.*/i",
"quantity": "/[+-]?([0-9]+,*\\.*)+/i",
"price": "/[+-]?([0-9]+,*\\.*)+/i",
"unit": "/.*/i",
"total": "/[+-]?([0-9]+,*\\.*)+/i",
"tax": "/[+-]?([0-9]+,*\\.*)+/i"
}
}
}
}

View File

@ -10,14 +10,26 @@
"cabinet labels", "paper towels", "cleaning supplies", "sticky tack",
"adhesive putty", "wall calendar"
],
"de": []
"de": [
"Büromaterial", "Bleistift", "Kugelschreiber", "Notizbuch", "Notiz", "Textmarker",
"Radiergummi", "Büroklammer", "Foldback-Klammer", "Heftklammern", "Hefter", "Klebebandabroller",
"Tesafilm", "Gummibänder", "Marker", "Whiteboard-Marker",
"Whiteboard-Radiergummi", "Schreibtischorganizer", "Kalender", "Schreibtischkalender",
"Aktenordner", "Ordner", "Hängeregistratur", "Umschlag", "Briefmarke",
"Schere", "Taschenrechner", "Lineal", "Mülleimer", "Abfalleimer",
"Schranketiketten", "Papierhandtücher", "Putzmittel", "Knetklebe", "Haftmasse",
"Wandkalender"
]
},
"it_supplies": {
"en": [
"keyboard", "mouse", "mice", "USB drive", "network cable", "toner",
"printer paper", "ink", "cartridge"
],
"de": []
"de": [
"Tastatur", "Maus", "Mäuse", "USB-Laufwerk", "Netzwerkkabel", "Toner",
"Druckerpapier", "Tinte", "Patrone"
]
},
"it_equipment": {
"en": [
@ -25,13 +37,19 @@
"router", "webcam", "headset", "hard drive", "microphone", "macbook", "phone",
"cellphone", "mobile phone"
],
"de": []
"de": [
"PC", "Computer", "Laptop", "Monitor", "Switch", "Netzteil", "Server", "Drucker",
"Router", "Webcam", "Headset", "Festplatte", "Mikrofon", "Macbook", "Telefon",
"Handy", "Mobiltelefon"
]
},
"internet_phone": {
"en": [
"domain", "website", "web server", "phone", "internet", "cellphone"
],
"de": []
"de": [
"Domäne", "Website", "Webserver", "Telefon", "Internet", "Mobiltelefon"
]
},
"furniture": {
"en": [
@ -43,7 +61,15 @@
"bean bag", "stool", "cubby storage", "shoe rack", "coat rack", "futon",
"crib", "playpen"
],
"de": []
"de": [
"Sofa", "Sessel", "Tisch", "Stuhl", "Bett", "Nachttisch", "Kommode", "Kleiderschrank",
"Bücherregal", "Schreibtisch", "Schrank", "Couch", "Sessel", "Fernsehtisch", "Kücheninsel",
"Barhocker", "Badezimmer-Waschtisch", "Esszimmerschrank", "Kommode",
"Bank", "Kredenz", "Sideboard", "Ottomane", "Kopfteil", "Fußteil",
"Chaiselongue", "Terrassenmöbel", "Essgarnitur für draußen", "Hängematte",
"Sitzsack", "Hocker", "Schrankmöbel", "Schuhregal", "Garderobe", "Futon",
"Kinderbett", "Laufstall"
]
},
"appliances": {
"en": [
@ -59,7 +85,19 @@
"portable air conditioner", "hot water dispenser", "skillet",
"popcorn maker", "margarita machine", "deep fryer", "griddle", "scale"
],
"de": []
"de": [
"Kühlschrank", "Backofen", "Herd", "Mikrowelle", "Geschirrspüler", "Waschmaschine",
"Wäschetrockner", "Gefrierschrank", "Kaffeemaschine", "Toaster", "Mixer",
"Küchenmaschine", "Wasserkocher", "Reiskocher", "Langsamkocher",
"Toaster", "Klimaanlage", "Heizung", "Deckenventilator", "Staubsauger",
"Bügeleisen", "Haartrockner", "Lockenstab", "Rasierapparat",
"Luftreiniger", "Luftentfeuchter", "Luftbefeuchter", "Müllschlucker",
"Müllpresse", "Dunstabzugshaube", "Entsafter", "Mixer", "Grill",
"Brotbackautomat", "Eismaschine", "Wasserspender", "ductless mini-split system",
"Wandofen", "Induktionskochfeld", "Espressomaschine", "Dosenöffner",
"tragbares Klimagerät", "Heißwasserspender", "Bratpfanne",
"Popcornmaschine", "Margarita-Maschine", "Fritteuse", "Bratplatte", "Waage"
]
},
"cleaning": {
"en": [
@ -74,7 +112,18 @@
"furniture polish", "shoe polish", "stainless steel cleaner", "rust remover",
"grill brush", "lime scale remover", "rug cleaner", "furniture stain remover"
],
"de": []
"de": [
"Besen", "Mopp", "Kehrblech", "Eimer", "Schwamm", "Schrubber", "Lappen",
"Papierhandtücher", "Müllbeutel", "Mülleimer", "Staubsauger",
"Teppichreiniger", "Glasreiniger", "Reinigungsmittel", "Desinfektionstücher",
"Toilettenbürste", "Toilettenschüsselreiniger", "Badreiniger", "Fliesenreiniger",
"Backofenreiniger", "Geschirrspülmittel", "Waschmittel", "Weichspüler",
"Fleckenentferner", "Mülleimerauskleidung", "Backpulver", "Essig",
"Staubmaske", "Putzkorb", "Fensterabzieher", "Staubwedel",
"Fusselrolle", "Lufterfrischer", "Handschuhe", "Entfetter", "Bodenwachs",
"Möbelpolitur", "Schuhcreme", "Edelstahlreiniger", "Rostlöser",
"Grillbürste", "Kalkentferner", "Teppichreiniger", "Möbelfleckenentferner"
]
},
"marketing": {
"en": [
@ -82,7 +131,11 @@
"advertising", "social media", "market research", "marketing", "catalogue",
"catalog", "price list"
],
"de": []
"de": [
"Flugblatt", "Broschüre", "Artikel", "Messe", "Ausstellung", "Messe",
"Werbung", "Social Media", "Marktforschung", "Marketing", "Katalog",
"katalog", "preisliste"
]
},
"food": {
"en": [
@ -90,18 +143,26 @@
"cake", "ice cream", "pudding", "donut",
"nudle", "steak", "fish", "salat", "burger", "fries", "potato", "soup"
],
"de": []
"de": [
"Wein", "Bier", "Schnaps", "Wasser", "Cola", "Fanta", "Saft", "Sprite", "Kaffee",
"Kuchen", "Eis", "Pudding", "Donut",
"Nudel", "Steak", "Fisch", "Salat", "Burger", "Pommes", "Kartoffel", "Suppe"
]
},
"hotel": {
"en": [
"hotel", "motel", "hostel"
],
"de": []
"de": [
"Hotel", "Motel", "Herberge"
]
},
"travel": {
"en": [
"flight", "taxi", "train", "uber", "parking"
"flight", "taxi", "train", "uber", "parking", "garage"
],
"de": []
"de": [
"Flug", "Taxi", "Zug", "Uber", "Parken", "Garage"
]
}
}

View File

@ -51,7 +51,7 @@ Currently Karaka is still developing the first Alpha version. As soon as we have
General updates can be found in our info section at https://jingga.app/info and developer updates can be found in our developer section at https://jingga.app/dev. In our developer section you can also check out the automatically generated reports such as code coverage, code style, static analysis etc. as well as our code style guide lines and developer documentation.
* [Project Status](https://github.com/Karaka-Management/Organization-Guide/blob/master/Project/PROJECT.md)
* [Project Status](https://github.com/orgs/Karaka-Management/projects/10)
## Tech stack
@ -62,7 +62,7 @@ General updates can be found in our info section at https://jingga.app/info and
## Become a contributor
Karaka has a very open culture and we always welcome new people who share our philosophy in providing create solutions which just work. You can find the development process description which also describes how to become a contributer in the [Organization documentation](https://github.com/Karaka-Management/Organization-Guide/blob/master/Processes/Development.md).
Karaka has a very open culture and we always welcome new people who share our philosophy in providing create solutions which just work. You can find the development process description which also describes how to become a contributer in the [Organization documentation](https://github.com/Karaka-Management/Organization-Guide/blob/master/Processes/01_Development.md).
## Misc

View File

@ -19,4 +19,6 @@ return ['Navigation' => [
'InvoiceRecognition' => 'Invoice Recognition',
'Open' => 'Open',
'Upload' => 'Upload',
'PaymentTerms' => 'Payment Terms',
'ShippingTerms' => 'Shipping Terms',
]];

View File

@ -15,33 +15,22 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => 'تبوك',
'Addresses' => 'عناوين',
'Africa' => '',
'AlreadyPaid' => 'مدفوع بالفعل',
'America' => '',
'Amount' => '',
'Analyse' => '',
'Archive' => '',
'Articles' => '',
'Asia' => '',
'Attribute' => '',
'BaseTime' => '',
'Billing' => '',
'Bills' => 'فواتير',
'Bonus' => 'علاوة',
'CIS' => '',
'Cashback' => 'استرداد النقدي',
'City' => 'مدينة',
'Client' => 'عميل',
'ClientID' => 'معرف العميل',
'ComparisonTime' => '',
'Confirmation' => 'تأكيد',
'Country' => 'دولة',
'CreateBill' => '',
'Created' => 'خلقت',
'CreditCard' => 'بطاقة إئتمان',
'CreditNote' => 'اشعار دائن',
'Currency' => '',
'Customers' => '',
'Date' => 'تاريخ',
'Delivery' => 'توصيل',
'DeliveryNote' => 'مذكرة تسليم',
@ -50,13 +39,9 @@ return ['Billing' => [
'DiscountP' => 'خصم ٪',
'Due' => 'بسبب',
'Email' => '',
'Europe' => '',
'Filter' => '',
'Freightage' => 'شحن',
'General' => '',
'Gross' => 'أزداد',
'Invoice' => 'فاتورة',
'Invoices' => 'الفواتير',
'Item' => 'العنصر',
'Items' => 'أغراض',
'Language' => '',
@ -68,7 +53,6 @@ return ['Billing' => [
'Net' => 'شبكة',
'Offer' => 'عرض',
'Original' => '',
'Other' => '',
'Payment' => 'دفع',
'PaymentPlan' => '',
'Postal' => 'بريدي',
@ -78,9 +62,6 @@ return ['Billing' => [
'Profit' => 'ربح',
'Quantity' => 'كمية',
'Recipient' => 'متلقي',
'Region' => '',
'Rep' => '',
'Sales' => '',
'Select' => 'يختار',
'Shipment' => 'شحنة',
'Source' => 'مصدر',
@ -92,7 +73,5 @@ return ['Billing' => [
'Type' => 'نوع',
'Types' => '',
'Upload' => 'تحميل',
'Value' => '',
'Variation' => 'تفاوت',
'Zip' => 'أزيز',
]];

View File

@ -15,33 +15,22 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => 'Adresa',
'Addresses' => 'Adresy',
'Africa' => '',
'AlreadyPaid' => 'Již zaplatil',
'America' => '',
'Amount' => '',
'Analyse' => '',
'Archive' => '',
'Articles' => '',
'Asia' => '',
'Attribute' => '',
'BaseTime' => '',
'Billing' => '',
'Bills' => 'Účtenka',
'Bonus' => 'Bonus',
'CIS' => '',
'Cashback' => 'Hotovost',
'City' => 'Město',
'Client' => 'Klienta',
'ClientID' => 'ID klienta',
'ComparisonTime' => '',
'Confirmation' => 'potvrzení',
'Country' => 'Země',
'CreateBill' => '',
'Created' => 'Vytvořený',
'CreditCard' => 'Kreditní karta',
'CreditNote' => 'Dobropis',
'Currency' => '',
'Customers' => '',
'Date' => 'datum',
'Delivery' => 'dodávka',
'DeliveryNote' => 'Dodací list',
@ -50,13 +39,9 @@ return ['Billing' => [
'DiscountP' => 'Sleva%',
'Due' => 'Způsoben',
'Email' => '',
'Europe' => '',
'Filter' => '',
'Freightage' => 'Dopravné',
'General' => '',
'Gross' => 'Hrubý',
'Invoice' => 'Faktura',
'Invoices' => 'Faktury',
'Item' => 'Položka',
'Items' => 'Položky',
'Language' => '',
@ -68,7 +53,6 @@ return ['Billing' => [
'Net' => 'Síť',
'Offer' => 'Nabídka',
'Original' => '',
'Other' => '',
'Payment' => 'Způsob platby',
'PaymentPlan' => '',
'Postal' => 'Poštovní',
@ -78,9 +62,6 @@ return ['Billing' => [
'Profit' => 'Zisk',
'Quantity' => 'Množství',
'Recipient' => 'Příjemce',
'Region' => '',
'Rep' => '',
'Sales' => '',
'Select' => 'Vybrat',
'Shipment' => 'náklad',
'Source' => 'Zdroj',
@ -92,7 +73,5 @@ return ['Billing' => [
'Type' => 'Typ',
'Types' => '',
'Upload' => 'nahrát',
'Value' => '',
'Variation' => 'Variace',
'Zip' => 'Zip',
]];

View File

@ -15,33 +15,22 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => 'Adresse',
'Addresses' => 'Adresser',
'Africa' => '',
'AlreadyPaid' => 'Allerede betalt',
'America' => '',
'Amount' => '',
'Analyse' => '',
'Archive' => '',
'Articles' => '',
'Asia' => '',
'Attribute' => '',
'BaseTime' => '',
'Billing' => '',
'Bills' => 'Regninger.',
'Bonus' => 'Bonus',
'CIS' => '',
'Cashback' => 'Penge tilbage',
'City' => 'City.',
'Client' => 'Klient',
'ClientID' => 'Klient ID.',
'ComparisonTime' => '',
'Confirmation' => 'Bekræftelse',
'Country' => 'Land',
'CreateBill' => '',
'Created' => 'Oprettet',
'CreditCard' => 'Kreditkort',
'CreditNote' => 'Kreditnota',
'Currency' => '',
'Customers' => '',
'Date' => 'Dato',
'Delivery' => 'Levering',
'DeliveryNote' => 'Levering note',
@ -50,13 +39,9 @@ return ['Billing' => [
'DiscountP' => 'Rabat%',
'Due' => 'På grund',
'Email' => '',
'Europe' => '',
'Filter' => '',
'Freightage' => 'Gods',
'General' => '',
'Gross' => 'Brutto',
'Invoice' => 'Faktura',
'Invoices' => 'Fakturaer.',
'Item' => 'Vare',
'Items' => 'Varer',
'Language' => '',
@ -68,7 +53,6 @@ return ['Billing' => [
'Net' => 'Net',
'Offer' => 'Tilbud',
'Original' => '',
'Other' => '',
'Payment' => 'Betaling',
'PaymentPlan' => '',
'Postal' => 'Postal.',
@ -78,9 +62,6 @@ return ['Billing' => [
'Profit' => 'Profit',
'Quantity' => 'Antal',
'Recipient' => 'Modtager',
'Region' => '',
'Rep' => '',
'Sales' => '',
'Select' => 'Vælg',
'Shipment' => 'Forsendelse',
'Source' => 'Kilde',
@ -92,7 +73,5 @@ return ['Billing' => [
'Type' => 'Type',
'Types' => '',
'Upload' => 'Upload',
'Value' => '',
'Variation' => 'Variation',
'Zip' => 'Zip.',
]];

View File

@ -15,84 +15,79 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => 'Adresse',
'Addresses' => 'Adressen',
'Africa' => 'Africa',
'AlreadyPaid' => 'Bereits bezahlt',
'America' => 'Amerika',
'Amount' => 'Betrag',
'Analyse' => 'Analyse',
'Archive' => 'Archiev',
'Articles' => 'Artikel',
'Asia' => 'Asien',
'Attribute' => 'Attribute',
'BaseTime' => 'Basiszeit',
'Internal' => 'Intern',
'Error' => 'Fehler',
'Billing' => 'Rechnungsstellung',
'External' => 'Extern',
'Bills' => 'Rechnungen',
'Bonus' => 'Bonus',
'CIS' => 'CIS',
'Cashback' => 'Kennzeichnen',
'City' => 'Stadt',
'Client' => 'Kunde',
'ClientID' => 'Kunden ID',
'ComparisonTime' => 'Vergleichszeit',
'Confirmation' => 'Bestätigung',
'Country' => 'Land',
'CreateBill' => 'Erstelle Rechnung',
'Created' => 'Erstellt',
'CreditCard' => 'Kreditkarte',
'CreditNote' => 'Gutschrift',
'CreditNote' => 'Rechnungskorrektur',
'Currency' => 'Währung',
'Customers' => 'Kunden',
'Date' => 'Datum',
'Delivery' => 'Die Zustellung',
'Delivery' => 'Lieferung',
'DeliveryNote' => 'Lieferschein',
'DirectDebit' => 'DirectDeBIT.',
'DirectDebit' => 'Direktüberweisung.',
'Discount' => 'Rabatt',
'DiscountP' => 'Rabatt %',
'Due' => 'Fällig',
'Email' => 'Email',
'Europe' => 'Europa',
'Filter' => 'Filter',
'Freightage' => 'Fracht',
'General' => 'Allgemein',
'Gross' => 'Grob',
'Gross' => 'Brutto',
'Invoice' => 'Rechnung',
'Invoices' => 'Rechnungen',
'Item' => 'Artikel',
'Items' => 'Produkte',
'Language' => 'Sprache',
'Log' => 'Protokoll',
'Logs' => 'Protokoll',
'Logs' => 'Protokolle',
'Media' => 'Medien',
'MoneyTransfer' => 'Geldüberweisung',
'MoneyTransfer' => 'Überweisung',
'Name' => 'Name',
'Net' => 'Netz',
'Parse' => 'Rechnungserkennung',
'Offer' => 'Angebot',
'Original' => 'Original',
'Other' => 'Sonstige',
'Payment' => 'Zahlung',
'PaymentPlan' => 'Zahlungsplan',
'Postal' => 'Post',
'Prepaid' => 'Vorausbezahlt',
'Preview' => 'Vorschau',
'Price' => 'Preis',
'Profit' => 'Profitieren',
'Profit' => 'Gewinn',
'Quantity' => 'Menge',
'Recipient' => 'Empfänger',
'Region' => 'Region',
'Rep' => 'Vertreter',
'Sales' => 'Umsatz',
'Select' => 'Wählen',
'Shipment' => 'Sendung',
'Source' => 'Quelle',
'Supplier' => 'Anbieter',
'SupplierID' => 'Lieferanten ID',
'Tax' => 'Steuer',
'TaxP' => 'Steuer %',
'Margin' => 'Marge',
'TermsOfDelivery' => 'Lieferbedingungen',
'Total' => 'Gesamt',
'Type' => 'Typ',
'Types' => 'Typen',
'Upload' => 'Hochladen',
'Value' => 'Wert',
'Variation' => 'Variation',
'Zip' => 'Zip',
'Files' => 'Files',
'PaymentTerms' => 'Zahlungsbedingungen',
'ShippingTerms' => 'Lieferbedingungen',
'PaymentTerm' => 'Zahlungsbedingung',
'ShippingTerm' => 'Lieferbedingung',
'E_bill_items' => 'Es gibt ein Problem mit Ihren Artikeln.',
'E_bill_taxes' => 'Der Gesamtsteuerbetrag stimmt nicht mit dem Steuerbetrag der Elemente überein. Möglicherweise gibt es ein Problem mit den Steuersätzen oder zusätzlichen Posten.',
'E_bill_net' => 'Der Gesamtnettobetrag stimmt nicht mit dem Nettobetrag der Elemente überein. Mögliches Problem mit Steuersätzen oder zusätzlichen Positionen.',
'E_bill_gross' => 'Der Gesamtbruttobetrag stimmt nicht mit dem Bruttobetrag der Elemente überein. Mögliches Problem mit Steuersätzen oder zusätzlichen Positionen.',
'E_bill_unit' => 'Stückpreis stimmt nicht mit Gesamtpreis überein. Mögliche Probleme mit Preis, Menge oder Rabatten.',
]];

View File

@ -15,33 +15,22 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => 'Διεύθυνση',
'Addresses' => 'Διευθύνσεις',
'Africa' => '',
'AlreadyPaid' => 'Ήδη πληρωθεί',
'America' => '',
'Amount' => '',
'Analyse' => '',
'Archive' => '',
'Articles' => '',
'Asia' => '',
'Attribute' => '',
'BaseTime' => '',
'Billing' => '',
'Bills' => 'Λογαριασμοί',
'Bonus' => 'Δώρο',
'CIS' => '',
'Cashback' => 'Επιστροφή μετρητών',
'City' => 'Πόλη',
'Client' => 'Πελάτης',
'ClientID' => 'ταυτότητα πελάτη',
'ComparisonTime' => '',
'Confirmation' => 'Επιβεβαίωση',
'Country' => 'Χώρα',
'CreateBill' => '',
'Created' => 'Δημιουργήθηκε',
'CreditCard' => 'Πιστωτική κάρτα',
'CreditNote' => 'Πιστωτικό σημείωμα',
'Currency' => '',
'Customers' => '',
'Date' => 'Ημερομηνία',
'Delivery' => 'Διανομή',
'DeliveryNote' => 'Δελτίο παράδοσης',
@ -50,13 +39,9 @@ return ['Billing' => [
'DiscountP' => 'Έκπτωση%',
'Due' => 'Λόγω',
'Email' => '',
'Europe' => '',
'Filter' => '',
'Freightage' => 'Ναύλος',
'General' => '',
'Gross' => 'Ακαθάριστο',
'Invoice' => 'Τιμολόγιο',
'Invoices' => 'Τιμολόγια',
'Item' => 'Είδος',
'Items' => 'Αντικείμενα',
'Language' => '',
@ -68,7 +53,6 @@ return ['Billing' => [
'Net' => 'Καθαρά',
'Offer' => 'Προσφορά',
'Original' => '',
'Other' => '',
'Payment' => 'Πληρωμή',
'PaymentPlan' => '',
'Postal' => 'Ταχυδρομικός',
@ -78,9 +62,6 @@ return ['Billing' => [
'Profit' => 'Κέρδος',
'Quantity' => 'Ποσότητα',
'Recipient' => 'Παραλήπτης',
'Region' => '',
'Rep' => '',
'Sales' => '',
'Select' => 'Επιλέγω',
'Shipment' => 'Αποστολή',
'Source' => 'Πηγή',
@ -92,7 +73,5 @@ return ['Billing' => [
'Type' => 'Τύπος',
'Types' => '',
'Upload' => 'Μεταφόρτω',
'Value' => '',
'Variation' => 'Παραλλαγή',
'Zip' => 'Φερμουάρ',
]];

View File

@ -15,33 +15,25 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => 'Address',
'Addresses' => 'Addresses',
'Africa' => 'Africa',
'AlreadyPaid' => 'Already Paid',
'America' => 'America',
'Amount' => 'Amount',
'Analyse' => 'Analyse',
'Archive' => 'Archive',
'Articles' => 'Articles',
'Asia' => 'Asia',
'Attribute' => 'Attribute',
'BaseTime' => 'Base time',
'Internal' => 'Internal',
'Error' => 'Error',
'Billing' => 'Billing',
'External' => 'External',
'Bills' => 'Bills',
'Bonus' => 'Bonus',
'CIS' => 'CIS',
'Cashback' => 'Cash Back',
'City' => 'City',
'Client' => 'Client',
'ClientID' => 'Client ID',
'ComparisonTime' => 'Comparison time',
'Confirmation' => 'Confirmation',
'Country' => 'Country',
'CreateBill' => 'Create Bill',
'Created' => 'Created',
'CreditCard' => 'CreditCard',
'CreditNote' => 'Credit Note',
'Currency' => 'Currency',
'Customers' => 'Customers',
'Date' => 'Date',
'Delivery' => 'Delivery',
'DeliveryNote' => 'Delivery Note',
@ -50,13 +42,9 @@ return ['Billing' => [
'DiscountP' => 'Discount %',
'Due' => 'Due',
'Email' => 'Email',
'Europe' => 'Europe',
'Filter' => 'Filter',
'Freightage' => 'Freightage',
'General' => 'General',
'Gross' => 'Gross',
'Invoice' => 'Invoice',
'Invoices' => 'Invoices',
'Item' => 'Item',
'Items' => 'Items',
'Language' => 'Language',
@ -66,9 +54,9 @@ return ['Billing' => [
'MoneyTransfer' => 'Money Transfer',
'Name' => 'Name',
'Net' => 'Net',
'Parse' => 'Invoice recognition',
'Offer' => 'Offer',
'Original' => 'Original',
'Other' => 'Other',
'Payment' => 'Payment',
'PaymentPlan' => 'Payment Plan',
'Postal' => 'Postal',
@ -78,21 +66,28 @@ return ['Billing' => [
'Profit' => 'Profit',
'Quantity' => 'Quantity',
'Recipient' => 'Recipient',
'Region' => 'Region',
'Rep' => 'Rep.',
'Sales' => 'Sales',
'Select' => 'Select',
'Shipment' => 'Shipment',
'Source' => 'Source',
'Supplier' => 'Supplier',
'SupplierID' => 'Supplier ID',
'Tax' => 'Tax',
'TaxP' => 'Tax %',
'Margin' => 'Margin',
'TermsOfDelivery' => 'Terms Of Delivery',
'Total' => 'Total',
'Type' => 'Type',
'Types' => 'Types',
'Upload' => 'Upload',
'Value' => 'Value',
'Variation' => 'Variation',
'Zip' => 'Zip',
'Files' => 'Files',
'PaymentTerms' => 'Payment Terms',
'ShippingTerms' => 'Shipping Terms',
'PaymentTerm' => 'Payment Term',
'ShippingTerm' => 'Shipping Term',
'E_bill_items' => 'There is an issue with your bill items.',
'E_bill_taxes' => 'The total tax amount doesn\'t match the tax amount of the elements. Potential issue with tax rates or additional items.',
'E_bill_net' => 'The total net amount doesn\'t match the net amount of the elements. Potential issue with tax rates or additional items.',
'E_bill_gross' => 'The total gross amount doesn\'t match the gross amount of the elements. Potential issue with tax rates or additional items.',
'E_bill_unit' => 'Unit price doesn\'t match total price. Potential issues with price, quantity or discounts.',
]];

View File

@ -15,33 +15,22 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => 'Habla a',
'Addresses' => 'Direcciones',
'Africa' => '',
'AlreadyPaid' => 'Ya pagado',
'America' => '',
'Amount' => '',
'Analyse' => '',
'Archive' => '',
'Articles' => '',
'Asia' => '',
'Attribute' => '',
'BaseTime' => '',
'Billing' => '',
'Bills' => 'Facturas',
'Bonus' => 'Prima',
'CIS' => '',
'Cashback' => 'Devolución de dinero',
'City' => 'Ciudad',
'Client' => 'Cliente',
'ClientID' => 'Identificación del cliente',
'ComparisonTime' => '',
'Confirmation' => 'Confirmación',
'Country' => 'País',
'CreateBill' => '',
'Created' => 'Creado',
'CreditCard' => 'Tarjeta de crédito',
'CreditNote' => 'Nota de crédito',
'Currency' => '',
'Customers' => '',
'Date' => 'Fecha',
'Delivery' => 'Entrega',
'DeliveryNote' => 'Nota de entrega',
@ -50,13 +39,9 @@ return ['Billing' => [
'DiscountP' => 'Descuento%',
'Due' => 'Vencer',
'Email' => '',
'Europe' => '',
'Filter' => '',
'Freightage' => 'Flete',
'General' => '',
'Gross' => 'Bruto',
'Invoice' => 'Factura',
'Invoices' => 'Facturas',
'Item' => 'Articulo',
'Items' => 'Elementos',
'Language' => '',
@ -68,7 +53,6 @@ return ['Billing' => [
'Net' => 'Red',
'Offer' => 'Oferta',
'Original' => '',
'Other' => '',
'Payment' => 'Pago',
'PaymentPlan' => '',
'Postal' => 'Postal',
@ -78,9 +62,6 @@ return ['Billing' => [
'Profit' => 'Lucro',
'Quantity' => 'Cantidad',
'Recipient' => 'Recipiente',
'Region' => '',
'Rep' => '',
'Sales' => '',
'Select' => 'Seleccione',
'Shipment' => 'Envío',
'Source' => 'Fuente',
@ -92,7 +73,5 @@ return ['Billing' => [
'Type' => 'Escribe',
'Types' => '',
'Upload' => 'Subir',
'Value' => '',
'Variation' => 'Variación',
'Zip' => 'Cremallera',
]];

View File

@ -15,33 +15,22 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => 'Osoite',
'Addresses' => 'Osoitteet',
'Africa' => '',
'AlreadyPaid' => 'Jo maksettu',
'America' => '',
'Amount' => '',
'Analyse' => '',
'Archive' => '',
'Articles' => '',
'Asia' => '',
'Attribute' => '',
'BaseTime' => '',
'Billing' => '',
'Bills' => 'Laskut',
'Bonus' => 'Bonus',
'CIS' => '',
'Cashback' => 'Vaihtorahat',
'City' => 'Kaupunki',
'Client' => 'Asiakas',
'ClientID' => 'Asiakastunnus',
'ComparisonTime' => '',
'Confirmation' => 'Vahvistus',
'Country' => 'Maa',
'CreateBill' => '',
'Created' => 'Luotu',
'CreditCard' => 'Luottokortti',
'CreditNote' => 'Luottoluotto',
'Currency' => '',
'Customers' => '',
'Date' => 'Päivämäärä',
'Delivery' => 'Toimitus',
'DeliveryNote' => 'Saapumisilmoitus',
@ -50,13 +39,9 @@ return ['Billing' => [
'DiscountP' => 'Alennus %',
'Due' => 'Takia',
'Email' => '',
'Europe' => '',
'Filter' => '',
'Freightage' => 'Rahti',
'General' => '',
'Gross' => 'Ällöttävä',
'Invoice' => 'Lasku',
'Invoices' => 'Laskut',
'Item' => 'Kohde',
'Items' => 'Tuotteet',
'Language' => '',
@ -68,7 +53,6 @@ return ['Billing' => [
'Net' => 'Netto',
'Offer' => 'Tarjous',
'Original' => '',
'Other' => '',
'Payment' => 'Maksu',
'PaymentPlan' => '',
'Postal' => 'Posti-',
@ -78,9 +62,6 @@ return ['Billing' => [
'Profit' => 'Voitto',
'Quantity' => 'Määrä',
'Recipient' => 'Vastaanottaja',
'Region' => '',
'Rep' => '',
'Sales' => '',
'Select' => 'Valitse',
'Shipment' => 'Lähetys',
'Source' => 'Lähde',
@ -92,7 +73,5 @@ return ['Billing' => [
'Type' => 'Tyyppi',
'Types' => '',
'Upload' => 'Ladata',
'Value' => '',
'Variation' => 'Vaihtelu',
'Zip' => 'Postinumero',
]];

View File

@ -15,33 +15,22 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => 'Adresse',
'Addresses' => 'Adresses',
'Africa' => '',
'AlreadyPaid' => 'Déjà payé',
'America' => '',
'Amount' => '',
'Analyse' => '',
'Archive' => '',
'Articles' => '',
'Asia' => '',
'Attribute' => '',
'BaseTime' => '',
'Billing' => '',
'Bills' => 'Factures',
'Bonus' => 'Prime',
'CIS' => '',
'Cashback' => 'Remise en argent',
'City' => 'Ville',
'Client' => 'Client',
'ClientID' => 'identité du client',
'ComparisonTime' => '',
'Confirmation' => 'Confirmation',
'Country' => 'Pays',
'CreateBill' => '',
'Created' => 'Établi',
'CreditCard' => 'Carte de crédit',
'CreditNote' => 'Note de crédit',
'Currency' => '',
'Customers' => '',
'Date' => 'Date',
'Delivery' => 'Livraison',
'DeliveryNote' => 'Bon de livraison',
@ -50,13 +39,9 @@ return ['Billing' => [
'DiscountP' => 'Remise %',
'Due' => 'Dû',
'Email' => '',
'Europe' => '',
'Filter' => '',
'Freightage' => 'Fret',
'General' => '',
'Gross' => 'Brut',
'Invoice' => 'Facture d\'achat',
'Invoices' => 'Factures',
'Item' => 'Article',
'Items' => 'Articles',
'Language' => '',
@ -68,7 +53,6 @@ return ['Billing' => [
'Net' => 'Rapporter',
'Offer' => 'Offrir',
'Original' => '',
'Other' => '',
'Payment' => 'Paiement',
'PaymentPlan' => '',
'Postal' => 'Postal',
@ -78,9 +62,6 @@ return ['Billing' => [
'Profit' => 'Profit',
'Quantity' => 'Quantité',
'Recipient' => 'Destinataire',
'Region' => '',
'Rep' => '',
'Sales' => '',
'Select' => 'Sélectionner',
'Shipment' => 'Expédition',
'Source' => 'La source',
@ -92,7 +73,5 @@ return ['Billing' => [
'Type' => 'Taper',
'Types' => '',
'Upload' => 'Télécharger',
'Value' => '',
'Variation' => 'Variation',
'Zip' => 'Zipper',
]];

View File

@ -15,33 +15,22 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => 'Cím',
'Addresses' => 'Címek',
'Africa' => '',
'AlreadyPaid' => 'Fizetve',
'America' => '',
'Amount' => '',
'Analyse' => '',
'Archive' => '',
'Articles' => '',
'Asia' => '',
'Attribute' => '',
'BaseTime' => '',
'Billing' => '',
'Bills' => 'Számlák',
'Bonus' => 'Bónusz',
'CIS' => '',
'Cashback' => 'Pénzvisszafizetés',
'City' => 'Város',
'Client' => 'Ügyfél',
'ClientID' => 'Ügyfélazonosító',
'ComparisonTime' => '',
'Confirmation' => 'Megerősítés',
'Country' => 'Ország',
'CreateBill' => '',
'Created' => 'Létrehozott',
'CreditCard' => 'Hitelkártya',
'CreditNote' => 'Jóváírás',
'Currency' => '',
'Customers' => '',
'Date' => 'Dátum',
'Delivery' => 'Szállítás',
'DeliveryNote' => 'Fuvarlevél',
@ -50,13 +39,9 @@ return ['Billing' => [
'DiscountP' => 'Árengedmény%',
'Due' => 'Esedékes',
'Email' => '',
'Europe' => '',
'Filter' => '',
'Freightage' => 'Fuvardíj',
'General' => '',
'Gross' => 'Bruttó',
'Invoice' => 'Számla',
'Invoices' => 'Számlák',
'Item' => 'Tétel',
'Items' => 'Elemek',
'Language' => '',
@ -68,7 +53,6 @@ return ['Billing' => [
'Net' => 'Háló',
'Offer' => 'Ajánlat',
'Original' => '',
'Other' => '',
'Payment' => 'Fizetés',
'PaymentPlan' => '',
'Postal' => 'Postai',
@ -78,9 +62,6 @@ return ['Billing' => [
'Profit' => 'Nyereség',
'Quantity' => 'Mennyiség',
'Recipient' => 'Befogadó',
'Region' => '',
'Rep' => '',
'Sales' => '',
'Select' => 'Kiválaszt',
'Shipment' => 'Szállítmány',
'Source' => 'Forrás',
@ -92,7 +73,5 @@ return ['Billing' => [
'Type' => 'típus',
'Types' => '',
'Upload' => 'Feltöltés',
'Value' => '',
'Variation' => 'Variáció',
'Zip' => 'Postai irányítószám',
]];

View File

@ -15,33 +15,22 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => 'Indirizzo',
'Addresses' => 'Indirizzi',
'Africa' => '',
'AlreadyPaid' => 'Già pagato',
'America' => '',
'Amount' => '',
'Analyse' => '',
'Archive' => '',
'Articles' => '',
'Asia' => '',
'Attribute' => '',
'BaseTime' => '',
'Billing' => '',
'Bills' => 'Fatture',
'Bonus' => 'Bonus.',
'CIS' => '',
'Cashback' => 'Rimborso',
'City' => 'Città',
'Client' => 'Cliente',
'ClientID' => 'Identificativo cliente',
'ComparisonTime' => '',
'Confirmation' => 'Conferma',
'Country' => 'Nazione',
'CreateBill' => '',
'Created' => 'Creato',
'CreditCard' => 'Carta di credito',
'CreditNote' => 'Nota di credito',
'Currency' => '',
'Customers' => '',
'Date' => 'Data',
'Delivery' => 'Consegna',
'DeliveryNote' => 'Bolla d\'accompagnamento',
@ -50,13 +39,9 @@ return ['Billing' => [
'DiscountP' => 'Sconto%',
'Due' => 'Dovuto',
'Email' => '',
'Europe' => '',
'Filter' => '',
'Freightage' => 'Liberare',
'General' => '',
'Gross' => 'Schifoso',
'Invoice' => 'Fattura',
'Invoices' => 'Fatture',
'Item' => 'Elemento',
'Items' => 'Elementi',
'Language' => '',
@ -68,7 +53,6 @@ return ['Billing' => [
'Net' => 'Rete',
'Offer' => 'Offerta',
'Original' => '',
'Other' => '',
'Payment' => 'Pagamento',
'PaymentPlan' => '',
'Postal' => 'postale',
@ -78,9 +62,6 @@ return ['Billing' => [
'Profit' => 'Profitto',
'Quantity' => 'Quantità',
'Recipient' => 'Destinatario',
'Region' => '',
'Rep' => '',
'Sales' => '',
'Select' => 'Selezionare',
'Shipment' => 'Spedizione',
'Source' => 'Fonte',
@ -92,7 +73,5 @@ return ['Billing' => [
'Type' => 'Tipo',
'Types' => '',
'Upload' => 'Caricamento',
'Value' => '',
'Variation' => 'Variazione',
'Zip' => 'Cerniera lampo',
]];

View File

@ -15,33 +15,22 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => '住所',
'Addresses' => 'アドレス',
'Africa' => '',
'AlreadyPaid' => '既に支払いました',
'America' => '',
'Amount' => '',
'Analyse' => '',
'Archive' => '',
'Articles' => '',
'Asia' => '',
'Attribute' => '',
'BaseTime' => '',
'Billing' => '',
'Bills' => 'bill',
'Bonus' => 'ボーナス',
'CIS' => '',
'Cashback' => 'キャッシュバック',
'City' => '市',
'Client' => 'クライアント',
'ClientID' => 'クライアントID',
'ComparisonTime' => '',
'Confirmation' => '確認',
'Country' => '国',
'CreateBill' => '',
'Created' => '作成した',
'CreditCard' => 'クレジットカード',
'CreditNote' => 'クレジットノート',
'Currency' => '',
'Customers' => '',
'Date' => '日にち',
'Delivery' => '配達',
'DeliveryNote' => '配達メモ',
@ -50,13 +39,9 @@ return ['Billing' => [
'DiscountP' => '割引 ',
'Due' => '期限',
'Email' => '',
'Europe' => '',
'Filter' => '',
'Freightage' => 'fre fre',
'General' => '',
'Gross' => 'きもい',
'Invoice' => '請求書',
'Invoices' => '請求書',
'Item' => 'アイテム',
'Items' => 'アイテム',
'Language' => '',
@ -68,7 +53,6 @@ return ['Billing' => [
'Net' => 'ネット',
'Offer' => 'オファー',
'Original' => '',
'Other' => '',
'Payment' => '支払い',
'PaymentPlan' => '',
'Postal' => '郵便',
@ -78,9 +62,6 @@ return ['Billing' => [
'Profit' => '利益',
'Quantity' => '量',
'Recipient' => '受信者',
'Region' => '',
'Rep' => '',
'Sales' => '',
'Select' => '選択する',
'Shipment' => '出荷',
'Source' => 'ソース',
@ -92,7 +73,5 @@ return ['Billing' => [
'Type' => 'タイプ',
'Types' => '',
'Upload' => 'アップロード',
'Value' => '',
'Variation' => '変化',
'Zip' => 'ジップ',
]];

View File

@ -15,33 +15,22 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => '주소',
'Addresses' => '구애',
'Africa' => '',
'AlreadyPaid' => '이미 지불',
'America' => '',
'Amount' => '',
'Analyse' => '',
'Archive' => '',
'Articles' => '',
'Asia' => '',
'Attribute' => '',
'BaseTime' => '',
'Billing' => '',
'Bills' => '청구서',
'Bonus' => '보너스',
'CIS' => '',
'Cashback' => '현금',
'City' => '도시',
'Client' => '고객',
'ClientID' => '클라이언트 ID.',
'ComparisonTime' => '',
'Confirmation' => '확인',
'Country' => '국가',
'CreateBill' => '',
'Created' => '만들어진',
'CreditCard' => '신용 카드',
'CreditNote' => '신용 노트',
'Currency' => '',
'Customers' => '',
'Date' => '날짜',
'Delivery' => '배달',
'DeliveryNote' => '배달 메모',
@ -50,13 +39,9 @@ return ['Billing' => [
'DiscountP' => '할인 %',
'Due' => '로 인한',
'Email' => '',
'Europe' => '',
'Filter' => '',
'Freightage' => '화물',
'General' => '',
'Gross' => '역겨운',
'Invoice' => '송장',
'Invoices' => '송장',
'Item' => '안건',
'Items' => '항목',
'Language' => '',
@ -68,7 +53,6 @@ return ['Billing' => [
'Net' => '그물',
'Offer' => '권하다',
'Original' => '',
'Other' => '',
'Payment' => '지불',
'PaymentPlan' => '',
'Postal' => '우편 엽서',
@ -78,9 +62,6 @@ return ['Billing' => [
'Profit' => '이익',
'Quantity' => '수량',
'Recipient' => '받는 사람',
'Region' => '',
'Rep' => '',
'Sales' => '',
'Select' => '선택하다',
'Shipment' => '선적',
'Source' => '원천',
@ -92,7 +73,5 @@ return ['Billing' => [
'Type' => '유형',
'Types' => '',
'Upload' => '업로드',
'Value' => '',
'Variation' => '변화',
'Zip' => '지퍼',
]];

View File

@ -15,33 +15,22 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => 'Adresse',
'Addresses' => 'Adresser',
'Africa' => '',
'AlreadyPaid' => 'Allerede betalt',
'America' => '',
'Amount' => '',
'Analyse' => '',
'Archive' => '',
'Articles' => '',
'Asia' => '',
'Attribute' => '',
'BaseTime' => '',
'Billing' => '',
'Bills' => 'Regninger',
'Bonus' => 'Bonus',
'CIS' => '',
'Cashback' => 'Penger tilbake',
'City' => 'By',
'Client' => 'Klient',
'ClientID' => 'klient-ID',
'ComparisonTime' => '',
'Confirmation' => 'Bekreftelse',
'Country' => 'Land',
'CreateBill' => '',
'Created' => 'Opprettet',
'CreditCard' => 'Kredittkort',
'CreditNote' => 'Kredittnota',
'Currency' => '',
'Customers' => '',
'Date' => 'Dato',
'Delivery' => 'Leveranse',
'DeliveryNote' => 'Leveringsnotat',
@ -50,13 +39,9 @@ return ['Billing' => [
'DiscountP' => 'Rabatt%',
'Due' => 'På grunn av det',
'Email' => '',
'Europe' => '',
'Filter' => '',
'Freightage' => 'Frakt',
'General' => '',
'Gross' => 'Ekkelt',
'Invoice' => 'Faktura',
'Invoices' => 'Fakturaer',
'Item' => 'Punkt',
'Items' => 'Elementer',
'Language' => '',
@ -68,7 +53,6 @@ return ['Billing' => [
'Net' => 'Nett',
'Offer' => 'By på',
'Original' => '',
'Other' => '',
'Payment' => 'innbetaling',
'PaymentPlan' => '',
'Postal' => 'Postal.',
@ -78,9 +62,6 @@ return ['Billing' => [
'Profit' => 'Profitt',
'Quantity' => 'Mengde',
'Recipient' => 'Mottaker',
'Region' => '',
'Rep' => '',
'Sales' => '',
'Select' => 'Plukke ut',
'Shipment' => 'Forsendelse',
'Source' => 'Kilde',
@ -92,7 +73,5 @@ return ['Billing' => [
'Type' => 'Type',
'Types' => '',
'Upload' => 'Laste opp',
'Value' => '',
'Variation' => 'Variasjon',
'Zip' => 'Glidelås',
]];

View File

@ -15,33 +15,22 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => 'Adres',
'Addresses' => 'Adresy',
'Africa' => '',
'AlreadyPaid' => 'Już zapłacone',
'America' => '',
'Amount' => '',
'Analyse' => '',
'Archive' => '',
'Articles' => '',
'Asia' => '',
'Attribute' => '',
'BaseTime' => '',
'Billing' => '',
'Bills' => 'Rachunki',
'Bonus' => 'Premia',
'CIS' => '',
'Cashback' => 'Zwrot gotówki',
'City' => 'Miasto',
'Client' => 'Klient',
'ClientID' => 'Identyfikator klienta',
'ComparisonTime' => '',
'Confirmation' => 'Potwierdzenie',
'Country' => 'Kraj',
'CreateBill' => '',
'Created' => 'Utworzony',
'CreditCard' => 'Karta kredytowa',
'CreditNote' => 'Uwaga kredytowa',
'Currency' => '',
'Customers' => '',
'Date' => 'Data',
'Delivery' => 'Dostawa',
'DeliveryNote' => 'Dowód dostawy',
@ -50,13 +39,9 @@ return ['Billing' => [
'DiscountP' => 'Zniżka %',
'Due' => 'Z powodu',
'Email' => '',
'Europe' => '',
'Filter' => '',
'Freightage' => 'Frachtowanie',
'General' => '',
'Gross' => 'Brutto',
'Invoice' => 'Faktura',
'Invoices' => 'Faktury',
'Item' => 'Przedmiot',
'Items' => 'Przedmiotów',
'Language' => '',
@ -68,7 +53,6 @@ return ['Billing' => [
'Net' => 'Internet',
'Offer' => 'Oferta',
'Original' => '',
'Other' => '',
'Payment' => 'Zapłata',
'PaymentPlan' => '',
'Postal' => 'Pocztowy',
@ -78,9 +62,6 @@ return ['Billing' => [
'Profit' => 'Zysk',
'Quantity' => 'Ilość',
'Recipient' => 'Odbiorca',
'Region' => '',
'Rep' => '',
'Sales' => '',
'Select' => 'Wybierać',
'Shipment' => 'Wysyłka',
'Source' => 'Źródło',
@ -92,7 +73,5 @@ return ['Billing' => [
'Type' => 'Rodzaj',
'Types' => '',
'Upload' => 'Wgrywać',
'Value' => '',
'Variation' => 'Zmiana',
'Zip' => 'Zamek błyskawiczny',
]];

View File

@ -15,33 +15,22 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => 'Endereço',
'Addresses' => 'Endereços',
'Africa' => '',
'AlreadyPaid' => 'Já pago',
'America' => '',
'Amount' => '',
'Analyse' => '',
'Archive' => '',
'Articles' => '',
'Asia' => '',
'Attribute' => '',
'BaseTime' => '',
'Billing' => '',
'Bills' => 'Notas',
'Bonus' => 'Bônus',
'CIS' => '',
'Cashback' => 'Dinheiro de volta',
'City' => 'Cidade',
'Client' => 'Cliente',
'ClientID' => 'ID do Cliente',
'ComparisonTime' => '',
'Confirmation' => 'Confirmação',
'Country' => 'País',
'CreateBill' => '',
'Created' => 'Criado',
'CreditCard' => 'Cartão de crédito',
'CreditNote' => 'Nota de crédito',
'Currency' => '',
'Customers' => '',
'Date' => 'Encontro',
'Delivery' => 'Entrega',
'DeliveryNote' => 'Nota de entrega',
@ -50,13 +39,9 @@ return ['Billing' => [
'DiscountP' => 'Desconto%',
'Due' => 'Vencimento',
'Email' => '',
'Europe' => '',
'Filter' => '',
'Freightage' => 'Freightage',
'General' => '',
'Gross' => 'Bruto',
'Invoice' => 'Fatura',
'Invoices' => 'Faturas',
'Item' => 'Item',
'Items' => 'Itens',
'Language' => '',
@ -68,7 +53,6 @@ return ['Billing' => [
'Net' => 'Internet',
'Offer' => 'Oferta',
'Original' => '',
'Other' => '',
'Payment' => 'Pagamento',
'PaymentPlan' => '',
'Postal' => 'Postal',
@ -78,9 +62,6 @@ return ['Billing' => [
'Profit' => 'Lucro',
'Quantity' => 'Quantidade',
'Recipient' => 'Destinatário',
'Region' => '',
'Rep' => '',
'Sales' => '',
'Select' => 'Selecione.',
'Shipment' => 'envio',
'Source' => 'Fonte',
@ -92,7 +73,5 @@ return ['Billing' => [
'Type' => 'Modelo',
'Types' => '',
'Upload' => 'Envio',
'Value' => '',
'Variation' => 'Variação',
'Zip' => 'Fecho eclair',
]];

View File

@ -15,33 +15,22 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => 'Адрес',
'Addresses' => 'Адреса',
'Africa' => '',
'AlreadyPaid' => 'Уже оплачено',
'America' => '',
'Amount' => '',
'Analyse' => '',
'Archive' => '',
'Articles' => '',
'Asia' => '',
'Attribute' => '',
'BaseTime' => '',
'Billing' => '',
'Bills' => 'Счета',
'Bonus' => 'Бонус',
'CIS' => '',
'Cashback' => 'Возврат наличных',
'City' => 'Город',
'Client' => 'Клиент',
'ClientID' => 'ID клиента',
'ComparisonTime' => '',
'Confirmation' => 'Подтверждение',
'Country' => 'Страна',
'CreateBill' => '',
'Created' => 'Созданный',
'CreditCard' => 'Кредитная карта',
'CreditNote' => 'Кредитная нота',
'Currency' => '',
'Customers' => '',
'Date' => 'Дата',
'Delivery' => 'Доставка',
'DeliveryNote' => 'Накладная',
@ -50,13 +39,9 @@ return ['Billing' => [
'DiscountP' => 'Скидка %',
'Due' => 'Должное',
'Email' => '',
'Europe' => '',
'Filter' => '',
'Freightage' => 'Фрахты',
'General' => '',
'Gross' => 'Валовой',
'Invoice' => 'Счет',
'Invoices' => 'Счета',
'Item' => 'Пункт',
'Items' => 'Предметы',
'Language' => '',
@ -68,7 +53,6 @@ return ['Billing' => [
'Net' => 'Сеть',
'Offer' => 'Предложение',
'Original' => '',
'Other' => '',
'Payment' => 'Оплата',
'PaymentPlan' => '',
'Postal' => 'Почтовый',
@ -78,9 +62,6 @@ return ['Billing' => [
'Profit' => 'Выгода',
'Quantity' => 'Количество',
'Recipient' => 'Получатель',
'Region' => '',
'Rep' => '',
'Sales' => '',
'Select' => 'Выбирать',
'Shipment' => 'Отгрузка',
'Source' => 'Источник',
@ -92,7 +73,5 @@ return ['Billing' => [
'Type' => 'Тип',
'Types' => '',
'Upload' => 'Загрузить',
'Value' => '',
'Variation' => 'Вариация',
'Zip' => 'Zip.',
]];

View File

@ -15,33 +15,22 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => 'Adress',
'Addresses' => 'Adresser',
'Africa' => '',
'AlreadyPaid' => 'Redan betalat',
'America' => '',
'Amount' => '',
'Analyse' => '',
'Archive' => '',
'Articles' => '',
'Asia' => '',
'Attribute' => '',
'BaseTime' => '',
'Billing' => '',
'Bills' => 'Räkningar',
'Bonus' => 'Bonus',
'CIS' => '',
'Cashback' => 'Pengar tillbaka',
'City' => 'Stad',
'Client' => 'Klient',
'ClientID' => 'Klient ID',
'ComparisonTime' => '',
'Confirmation' => 'Bekräftelse',
'Country' => 'Land',
'CreateBill' => '',
'Created' => 'Skapad',
'CreditCard' => 'Kreditkort',
'CreditNote' => 'Kreditanteckning',
'Currency' => '',
'Customers' => '',
'Date' => 'Datum',
'Delivery' => 'Leverans',
'DeliveryNote' => 'Leveransanteckning',
@ -50,13 +39,9 @@ return ['Billing' => [
'DiscountP' => 'Rabatt%',
'Due' => 'På grund av',
'Email' => '',
'Europe' => '',
'Filter' => '',
'Freightage' => 'Frakt',
'General' => '',
'Gross' => 'Äckligt',
'Invoice' => 'Faktura',
'Invoices' => 'Fakturor',
'Item' => 'Artikel',
'Items' => 'Objekt',
'Language' => '',
@ -68,7 +53,6 @@ return ['Billing' => [
'Net' => 'Netto',
'Offer' => 'Erbjudande',
'Original' => '',
'Other' => '',
'Payment' => 'Betalning',
'PaymentPlan' => '',
'Postal' => 'Post',
@ -78,9 +62,6 @@ return ['Billing' => [
'Profit' => 'Vinst',
'Quantity' => 'Kvantitet',
'Recipient' => 'Mottagare',
'Region' => '',
'Rep' => '',
'Sales' => '',
'Select' => 'Välj',
'Shipment' => 'Sändning',
'Source' => 'Källa',
@ -92,7 +73,5 @@ return ['Billing' => [
'Type' => 'Typ',
'Types' => '',
'Upload' => 'Ladda upp',
'Value' => '',
'Variation' => 'Variation',
'Zip' => 'Blixtlås',
]];

View File

@ -15,33 +15,22 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => 'ที่อยู่',
'Addresses' => 'ที่อยู่',
'Africa' => '',
'AlreadyPaid' => 'จ่ายแล้ว',
'America' => '',
'Amount' => '',
'Analyse' => '',
'Archive' => '',
'Articles' => '',
'Asia' => '',
'Attribute' => '',
'BaseTime' => '',
'Billing' => '',
'Bills' => 'การเรียกเก็บเงิน',
'Bonus' => 'โบนัส',
'CIS' => '',
'Cashback' => 'เงินคืน',
'City' => 'เมือง',
'Client' => 'ลูกค้า',
'ClientID' => 'รหัสลูกค้า',
'ComparisonTime' => '',
'Confirmation' => 'การยืนยัน',
'Country' => 'ประเทศ',
'CreateBill' => '',
'Created' => 'สร้าง',
'CreditCard' => 'บัตรเครดิต',
'CreditNote' => 'ใบลดหนี้',
'Currency' => '',
'Customers' => '',
'Date' => 'วันที่',
'Delivery' => 'จัดส่ง',
'DeliveryNote' => 'บันทึกการส่งมอบ',
@ -50,13 +39,9 @@ return ['Billing' => [
'DiscountP' => 'การลดราคา %',
'Due' => 'เนื่องจาก',
'Email' => '',
'Europe' => '',
'Filter' => '',
'Freightage' => 'การขนส่งสินค้า',
'General' => '',
'Gross' => 'ทั้งหมด',
'Invoice' => 'ใบแจ้งหนี้',
'Invoices' => 'ใบแจ้งหนี้',
'Item' => 'สิ่งของ',
'Items' => 'รายการ',
'Language' => '',
@ -68,7 +53,6 @@ return ['Billing' => [
'Net' => 'สุทธิ',
'Offer' => 'เสนอ',
'Original' => '',
'Other' => '',
'Payment' => 'การชำระเงิน',
'PaymentPlan' => '',
'Postal' => 'เกี่ยวกับการไปรษณีย์',
@ -78,9 +62,6 @@ return ['Billing' => [
'Profit' => 'กำไร',
'Quantity' => 'ปริมาณ',
'Recipient' => 'ผู้รับ',
'Region' => '',
'Rep' => '',
'Sales' => '',
'Select' => 'เลือก',
'Shipment' => 'การจัดส่ง',
'Source' => 'แหล่งที่มา',
@ -92,7 +73,5 @@ return ['Billing' => [
'Type' => 'พิมพ์',
'Types' => '',
'Upload' => 'ที่อัพโหลด',
'Value' => '',
'Variation' => 'การเปลี่ยนแปลง',
'Zip' => 'ซิป',
]];

View File

@ -15,33 +15,22 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => 'Adres',
'Addresses' => 'Adresler',
'Africa' => '',
'AlreadyPaid' => 'Zaten ödendi',
'America' => '',
'Amount' => '',
'Analyse' => '',
'Archive' => '',
'Articles' => '',
'Asia' => '',
'Attribute' => '',
'BaseTime' => '',
'Billing' => '',
'Bills' => 'Faturalar',
'Bonus' => 'Bonus',
'CIS' => '',
'Cashback' => 'Nakit para',
'City' => 'Şehir',
'Client' => 'Müşteri',
'ClientID' => 'Müşteri Kimliği',
'ComparisonTime' => '',
'Confirmation' => 'Onayla',
'Country' => 'Ülke',
'CreateBill' => '',
'Created' => 'Yaratılmış',
'CreditCard' => 'Kredi kartı',
'CreditNote' => 'Kredi notu',
'Currency' => '',
'Customers' => '',
'Date' => 'Tarih',
'Delivery' => 'Teslimat',
'DeliveryNote' => 'Teslimat notu',
@ -50,13 +39,9 @@ return ['Billing' => [
'DiscountP' => 'İndirim %',
'Due' => 'Vadesi dolmuş',
'Email' => '',
'Europe' => '',
'Filter' => '',
'Freightage' => 'Yük',
'General' => '',
'Gross' => 'Brüt',
'Invoice' => 'Fatura',
'Invoices' => 'Faturalar',
'Item' => 'Kalem',
'Items' => 'Öğeler',
'Language' => '',
@ -68,7 +53,6 @@ return ['Billing' => [
'Net' => 'Ağ',
'Offer' => 'Teklif',
'Original' => '',
'Other' => '',
'Payment' => 'Ödeme',
'PaymentPlan' => '',
'Postal' => 'Posta',
@ -78,9 +62,6 @@ return ['Billing' => [
'Profit' => 'Kâr',
'Quantity' => 'Miktar',
'Recipient' => 'Alıcı',
'Region' => '',
'Rep' => '',
'Sales' => '',
'Select' => 'Seçme',
'Shipment' => 'gönderi',
'Source' => 'Kaynak',
@ -92,7 +73,5 @@ return ['Billing' => [
'Type' => 'Tip',
'Types' => '',
'Upload' => 'Yüklemek',
'Value' => '',
'Variation' => 'varyasyon',
'Zip' => 'Zip',
]];

View File

@ -15,33 +15,22 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => 'Адреса',
'Addresses' => 'Адреси',
'Africa' => '',
'AlreadyPaid' => 'Вже оплачено',
'America' => '',
'Amount' => '',
'Analyse' => '',
'Archive' => '',
'Articles' => '',
'Asia' => '',
'Attribute' => '',
'BaseTime' => '',
'Billing' => '',
'Bills' => 'Векселі',
'Bonus' => 'Бонус',
'CIS' => '',
'Cashback' => 'Готівка',
'City' => 'Місто',
'Client' => 'Клієнт',
'ClientID' => 'Ідентифікатор клієнта',
'ComparisonTime' => '',
'Confirmation' => 'Підтвердження',
'Country' => 'Країна',
'CreateBill' => '',
'Created' => 'Створений',
'CreditCard' => 'Кредитна карта',
'CreditNote' => 'Кредитове авізо',
'Currency' => '',
'Customers' => '',
'Date' => 'Дата',
'Delivery' => 'Доставка',
'DeliveryNote' => 'Накладна',
@ -50,13 +39,9 @@ return ['Billing' => [
'DiscountP' => 'Знижка%',
'Due' => 'Заборгованість',
'Email' => '',
'Europe' => '',
'Filter' => '',
'Freightage' => 'Фрахт',
'General' => '',
'Gross' => 'Валовий',
'Invoice' => 'Рахунок-фактура',
'Invoices' => 'Рахунки-фактури',
'Item' => 'Елемент',
'Items' => 'Предмети',
'Language' => '',
@ -68,7 +53,6 @@ return ['Billing' => [
'Net' => 'Сітка',
'Offer' => 'Пропозиція',
'Original' => '',
'Other' => '',
'Payment' => 'Платіж',
'PaymentPlan' => '',
'Postal' => 'Поштовий',
@ -78,9 +62,6 @@ return ['Billing' => [
'Profit' => 'Прибуток',
'Quantity' => 'Кількість',
'Recipient' => 'Одержувач',
'Region' => '',
'Rep' => '',
'Sales' => '',
'Select' => 'Вибирати',
'Shipment' => 'Відвантаження',
'Source' => 'Джерело',
@ -92,7 +73,5 @@ return ['Billing' => [
'Type' => 'Тип',
'Types' => '',
'Upload' => 'Завантажувати',
'Value' => '',
'Variation' => 'Зміна',
'Zip' => 'Блиск',
]];

View File

@ -15,33 +15,22 @@ declare(strict_types=1);
return ['Billing' => [
'Address' => '地址',
'Addresses' => '地址',
'Africa' => '',
'AlreadyPaid' => '已付款',
'America' => '',
'Amount' => '',
'Analyse' => '',
'Archive' => '',
'Articles' => '',
'Asia' => '',
'Attribute' => '',
'BaseTime' => '',
'Billing' => '',
'Bills' => '账单',
'Bonus' => '奖金',
'CIS' => '',
'Cashback' => '返现金',
'City' => '城市',
'Client' => '客户',
'ClientID' => '客户ID',
'ComparisonTime' => '',
'Confirmation' => '确认',
'Country' => '国家',
'CreateBill' => '',
'Created' => '创造了',
'CreditCard' => '信用卡',
'CreditNote' => '信用票据',
'Currency' => '',
'Customers' => '',
'Date' => '日期',
'Delivery' => '交货',
'DeliveryNote' => '送货单',
@ -50,13 +39,9 @@ return ['Billing' => [
'DiscountP' => '折扣 ',
'Due' => '到期的',
'Email' => '',
'Europe' => '',
'Filter' => '',
'Freightage' => 'FRIGUTAGE.',
'General' => '',
'Gross' => '总的',
'Invoice' => '发票',
'Invoices' => '发票',
'Item' => '物品',
'Items' => '项目',
'Language' => '',
@ -68,7 +53,6 @@ return ['Billing' => [
'Net' => '网',
'Offer' => '提供',
'Original' => '',
'Other' => '',
'Payment' => '支付',
'PaymentPlan' => '',
'Postal' => '邮政',
@ -78,9 +62,6 @@ return ['Billing' => [
'Profit' => '利润',
'Quantity' => '数量',
'Recipient' => '接受者',
'Region' => '',
'Rep' => '',
'Sales' => '',
'Select' => '选择',
'Shipment' => '运输',
'Source' => '来源',
@ -92,7 +73,5 @@ return ['Billing' => [
'Type' => '类型',
'Types' => '',
'Upload' => '上传',
'Value' => '',
'Variation' => '变化',
'Zip' => '压缩',
]];

View File

@ -20,10 +20,10 @@ use phpOMS\Localization\ISO4217Enum;
use phpOMS\Localization\ISO639Enum;
use phpOMS\Uri\UriFactory;
$countryCodes = ISO3166TwoEnum::getConstants();
$countries = ISO3166NameEnum::getConstants();
$languages = ISO639Enum::getConstants();
$currencies = ISO4217Enum::getConstants();
$countryCodes = ISO3166TwoEnum::getConstants();
$countries = ISO3166NameEnum::getConstants();
$languages = ISO639Enum::getConstants();
$currencies = ISO4217Enum::getConstants();
/**
* @var \phpOMS\Views\View $this
@ -32,30 +32,59 @@ $media = $this->data['media'] ?? [];
/** @var \Modules\Billing\Models\Bill $bill */
$bill = $this->getData('bill') ?? new NullBill();
$elements = $bill->getElements();
$elements = $bill->elements;
$billTypes = $this->data['billtypes'] ?? [];
$archive = $bill->getFileByTypeName('original');
$archive = $bill->getFileByTypeName('internal');
/** @var \Modules\Auditor\Models\Audit */
$logs = $this->data['logs'] ?? [];
$editable = $bill->id === 0 || \in_array($bill->getStatus(), [BillStatus::DRAFT, BillStatus::UNPARSED]);
$editable = $bill->id === 0 || \in_array($bill->status, [BillStatus::DRAFT, BillStatus::UNPARSED]);
$disabled = $editable ? '' : ' disabled';
$isNew = $archive->id === 0;
echo $this->data['nav']->render(); ?>
<?php if (!$bill->isValid()) : ?>
<div class="row">
<div class="col-xs-12">
<section class="portlet hl-1">
<article class="hl-1">
<ul>
<?php if (!$bill->areElementsValid()) : ?>
<li><?= $this->getHtml('E_bill_items'); ?></li>
<?php endif; ?>
<?php if (!$bill->validateTaxAmountElements()) : ?>
<li><?= $this->getHtml('E_bill_taxes'); ?></li>
<?php endif; ?>
<?php if (!$bill->validateNetElements()) : ?>
<li><?= $this->getHtml('E_bill_net'); ?></li>
<?php endif; ?>
<?php if (!$bill->validateGrossElements()) : ?>
<li><?= $this->getHtml('E_bill_gross'); ?></li>
<?php endif; ?>
<?php if (!$bill->validatePriceQuantityElements()) : ?>
<li><?= $this->getHtml('E_bill_unit'); ?></li>
<?php endif; ?>
</ul>
</article>
</section>
</div>
</div>
<?php endif; ?>
<div class="tabview tab-2 col-simple">
<div class="box">
<ul class="tab-links">
<li><label for="c-tab-1"><?= $this->getHtml('Invoice'); ?></label></li>
<li><label for="c-tab-2"><?= $this->getHtml('Items'); ?></label></li>
<li><label for="c-tab-3"><?= $this->getHtml('Preview'); ?></label></li>
<li><label for="c-tab-4"><?= $this->getHtml('Archive'); ?></label></li>
<li><label for="c-tab-5"><?= $this->getHtml('Payment'); ?></label></li>
<li><label for="c-tab-6"><?= $this->getHtml('Media'); ?></label></li>
<li><label for="c-tab-7"><?= $this->getHtml('Logs'); ?></label></li>
<li><label for="c-tab-1"><?= $this->getHtml('Invoice'); ?></label>
<li><label for="c-tab-2"><?= $this->getHtml('Items'); ?></label>
<li><label for="c-tab-3"><?= $this->getHtml('Preview'); ?></label>
<?php if (!$isNew) : ?><li><label for="c-tab-4"><?= $this->getHtml('Archive'); ?></label><?php endif; ?>
<!--<li><label for="c-tab-5"><?= $this->getHtml('Payment'); ?></label>-->
<li><label for="c-tab-6"><?= $this->getHtml('Files'); ?></label>
<?php if (!$isNew && !empty($logs)) : ?><li><label for="c-tab-7"><?= $this->getHtml('Logs'); ?></label><?php endif; ?>
</ul>
</div>
<div class="tab-content col-simple">
@ -80,7 +109,7 @@ echo $this->data['nav']->render(); ?>
<label for="iCurrency"><?= $this->getHtml('Currency'); ?></label>
<select id="iCurrency" name="bill_currency"<?= $disabled; ?>>
<?php foreach ($currencies as $code => $currency) : $code = \substr($code, 1); ?>
<option value="<?= $this->printHtml($code); ?>"<?= $code === $bill->getCurrency() ? ' selected' : ''; ?>><?= $this->printHtml($currency); ?>
<option value="<?= $this->printHtml($code); ?>"<?= $code === $bill->currency ? ' selected' : ''; ?>><?= $this->printHtml($currency); ?>
<?php endforeach; ?>
</select>
</div>
@ -89,7 +118,7 @@ echo $this->data['nav']->render(); ?>
<label for="iSource"><?= $this->getHtml('Source'); ?></label>
<span class="input">
<button type="button" formaction="">
<i class="fa fa-book"></i>
<i class="g-icon">book</i>
</button>
<input type="text" id="iSource" name="bill_source"<?= $disabled; ?>>
</span>
@ -99,7 +128,7 @@ echo $this->data['nav']->render(); ?>
<label for="iBillType"><?= $this->getHtml('Type'); ?></label>
<select id="iBillType" name="bill_type"<?= $disabled; ?>>
<?php foreach ($billTypes as $type) : ?>
<option value="<?= $type->id; ?>"><?= $this->printHtml($type->getL11n()); ?>
<option value="<?= $type->id; ?>"<?= $type->id === $bill->type->id ? ' selected' : ''; ?>><?= $this->printHtml($type->getL11n()); ?>
<?php endforeach; ?>
</select>
</div>
@ -110,14 +139,14 @@ echo $this->data['nav']->render(); ?>
<div class="ipt-first">
<span class="input">
<button type="button" formaction="">
<i class="fa fa-book"></i>
<i class="g-icon">book</i>
</button>
<input type="text" id="iClient" name="bill_client" value="<?= $bill->client?->number ?? $bill->supplier?->number; ?>"<?= $disabled; ?>>
</span>
</div>
<?php if (($bill->client?->id ?? 0) > 0) : ?>
<div class="ipt-second">
<a class="button" href="<?= UriFactory::build('{/app}/sales/client/profile?id=' . $bill->client->id); ?>"><?= $this->getHtml('Client'); ?></a>
<a class="button" href="<?= UriFactory::build('{/base}/sales/client/view?id=' . $bill->client->id); ?>"><?= $this->getHtml('Client'); ?></a>
</div>
<?php endif; ?>
</div>
@ -266,44 +295,50 @@ echo $this->data['nav']->render(); ?>
<div class="row">
<div class="col-xs-12">
<section class="portlet">
<div class="portlet-head"><?= $this->getHtml('Invoice'); ?><i class="lni lni-download download btn end-xs"></i></div>
<div class="portlet-head"><?= $this->getHtml('Invoice'); ?><i class="g-icon download btn end-xs">download</i></div>
<div class="slider">
<table
id="invoiceElements"
class="default sticky"
data-action="<?= \phpOMS\Uri\UriFactory::build('{/api}billing/bill/element?{?}&csrf={$CSRF}'); ?>"
data-tag="form"
data-ui-container="tbody"
data-ui-element="tr"
data-on-change="1"
data-add-tpl=".oms-invoice-add">
<thead>
<tr>
<td>
<td><?= $this->getHtml('Item'); ?>
<td class="wf-100"><?= $this->getHtml('Name'); ?>
<td><?= $this->getHtml('Quantity'); ?>
<td style="min-width:150px"><?= $this->getHtml('Item'); ?>
<td class="wf-100" style="min-width:150px"><?= $this->getHtml('Name'); ?>
<td style="min-width:75px"><?= $this->getHtml('Quantity'); ?>
<td style="min-width:90px"><?= $this->getHtml('Discount'); ?>
<td style="min-width:90px"><?= $this->getHtml('DiscountP'); ?>
<td style="min-width:90px"><?= $this->getHtml('Bonus'); ?>
<td style="min-width:90px"><?= $this->getHtml('Tax'); ?>
<td style="min-width:75px"><?= $this->getHtml('Bonus'); ?>
<td style="min-width:90px"><?= $this->getHtml('Price'); ?>
<td style="min-width:75px"><?= $this->getHtml('TaxP'); ?>
<td><?= $this->getHtml('Net'); ?>
<td><?= $this->getHtml('Margin'); ?>
<tbody class="oms-ordercontainer">
<?php if ($editable) : ?>
<template class="oms-invoice-add">
<tr data-id="">
<td>
<i class="fa fa-chevron-up order-up"></i>
<i class="fa fa-chevron-down order-down"></i>
<i class="fa fa-times btn remove-form"></i>
<i class="g-icon order-up">expand_less</i>
<i class="g-icon order-down">expand_more</i>
<i class="g-icon btn remove-form">close</i>
<td><span class="input">
<button type="button" formaction="">
<label><i class="fa fa-book"></i></label>
</button><input type="text" autocomplete="off"></span>
<td><textarea autocomplete="off"></textarea>
<td><input type="number" step="any" value="" autocomplete="off">
<td><input type="number" step="0.01" value="" autocomplete="off">
<td><input type="number" min="-100" max="100" step="0.01" value="" autocomplete="off">
<td><input type="number" step="0.01" value="" autocomplete="off">
<td><input type="number" step="0.01" value="" autocomplete="off">
<label><i class="g-icon">book</i></label>
</button><input name="item_number" type="text" autocomplete="off"></span>
<td><textarea name="item_description" autocomplete="off"></textarea>
<td><input name="item_quantity" type="number" step="any" value="" autocomplete="off">
<td><input name="item_discountp" type="number" step="any" value="" autocomplete="off">
<td><input name="item_discountr" type="number" min="-100" max="100" step="0.01" value="" autocomplete="off">
<td><input name="item_bonus" type="number" step="any" value="" autocomplete="off">
<td><input name="item_price" type="number" step="any" value="" autocomplete="off">
<td><input name="item_taxr" type="number" step="any" value="" autocomplete="off">
<td>
<td>
</tr>
</template>
@ -311,42 +346,60 @@ echo $this->data['nav']->render(); ?>
<?php foreach ($elements as $element) : ?>
<tr>
<td><?php if ($editable) : ?>
<i class="fa fa-chevron-up order-up"></i>
<i class="fa fa-chevron-down order-down"></i>
<i class="fa fa-times btn remove-form"></i>
<i class="g-icon order-up">expand_less</i>
<i class="g-icon order-down">expand_more</i>
<i class="g-icon btn remove-form">close</i>
<?php endif; ?>
<td><span class="input"><button type="button" formaction=""><i class="fa fa-book"></i></button><input name="" type="text" value="<?= $element->itemNumber; ?>" required<?= $disabled; ?>></span>
<td><textarea required<?= $disabled; ?>><?= $element->itemName; ?></textarea>
<td><input name="" type="number" step="any" value="<?= $element->getQuantity(); ?>" required<?= $disabled; ?>>
<td><input name="" type="number" step="0.01"<?= $disabled; ?>>
<td><input name="" type="number" step="0.01"<?= $disabled; ?>>
<td><input name="" type="number" min="-100" max="100" step="0.01"<?= $disabled; ?>>
<td><input name="" type="number" step="0.01"<?= $disabled; ?>>
<td><input name="" type="number" step="0.01" value="<?= $element->singleSalesPriceNet->getFloat(); ?>"<?= $disabled; ?>>
<td><?= $this->getCurrency($element->totalSalesPriceNet); ?>
<td><span class="input">
<button type="button" formaction="">
<i class="g-icon">book</i>
</button><input name="item_number" autocomplete="off" type="text" value="<?= $element->itemNumber; ?>"<?= $disabled; ?>></span>
<td><textarea name="item_description" autocomplete="off"<?= $disabled; ?>><?= $element->itemName; ?></textarea>
<td><input name="item_quantity" autocomplete="off" type="number" step="any" value="<?= $element->quantity->sub($element->discountQ)->getAmount($element->container->quantityDecimals); ?>"<?= $disabled; ?>>
<td><input name="item_discountp" autocomplete="off" type="number" step="any" value="<?= $element->singleDiscountP->getAmount(); ?>"<?= $disabled; ?>>
<td><input name="item_discountr" autocomplete="off" type="number" step="any" value="<?= $element->singleDiscountR->getAmount(); ?>"<?= $disabled; ?>>
<td><input name="item_bonus" autocomplete="off" type="number" min="-100" max="100" step="0.01" value="<?= $element->discountQ->getAmount($element->container->quantityDecimals); ?>"<?= $disabled; ?>>
<td><input name="item_price" autocomplete="off" type="number" step="any" value="<?= $element->singleSalesPriceNet->getFloat(); ?>"<?= $disabled; ?>>
<td><input name="item_taxr" autocomplete="off" type="number" step="any" value="<?= $element->taxR->getAmount(); ?>"<?= $disabled; ?>>
<td><?= $this->getCurrency($element->totalSalesPriceNet, symbol: ''); ?>
<td><?= \number_format($element->totalSalesPriceNet->value === 0 ? 0 : (1 - $element->totalPurchasePriceNet->value / $element->totalSalesPriceNet->value) * 100, 2); ?>%
<?php endforeach; ?>
<?php if ($editable) : ?>
<tr data-id="0">
<td><i class="fa fa-chevron-up order-up"></i>
<i class="fa fa-chevron-down order-down"></i>
<i class="fa fa-times btn remove-form"></i>
<td><span class="input"><button type="button" formaction=""><i class="fa fa-book"></i></button><input type="text" autocomplete="off"></span>
<td><textarea autocomplete="off"></textarea>
<td><input type="number" step="any" value="" autocomplete="off">
<td><input type="number" step="0.01" value="" autocomplete="off">
<td><input type="number" min="-100" max="100" step="0.01" value="" autocomplete="off">
<td><input type="number" step="0.01" value="" autocomplete="off">
<td><input type="number" step="0.01" value="" autocomplete="off">
<td><input type="number" step="0.01" value="" autocomplete="off">
<td><i class="g-icon order-up">expand_less</i>
<i class="g-icon order-down">expand_more</i>
<i class="g-icon btn remove-form">close</i>
<td><span class="input">
<button type="button" formaction="">
<i class="g-icon">book</i></button><input name="item_number" type="text" autocomplete="off"></span>
<td><textarea name="item_description" autocomplete="off"></textarea>
<td><input name="item_quantity" type="number" step="any" value="" autocomplete="off">
<td><input name="item_discountp" type="number" step="0.01" value="" autocomplete="off">
<td><input name="item_discountr" type="number" min="-100" max="100" step="0.01" value="" autocomplete="off">
<td><input name="item_bonus" type="number" step="0.01" value="" autocomplete="off">
<td><input name="item_price" type="number" step="0.01" value="" autocomplete="off">
<td><input name="item_taxr" type="number" step="0.01" value="" autocomplete="off">
<td>
<td>
<?php endif; ?>
<tfoot>
<tr class="hl-2">
<td colspan="3"><?= $this->getHtml('Total'); ?>
<td>
<td><?= $bill->netDiscount->getAmount(2); ?>
<td><?= \number_format($bill->netDiscount->value === 0 ? 0 : ($bill->netDiscount->value / ($bill->netSales->value + $bill->netDiscount->value)) * 100, 2); ?>%
<td>
<td>
<td><?= $bill->taxP->getAmount(2); ?>
<td><?= $bill->netSales->getAmount(2); ?>
<td><?= \number_format($bill->netSales->value === 0 ? 0 : (1 - $bill->netCosts->value / $bill->netSales->value) * 100, 2); ?>%
</table>
</div>
</section>
<?php if ($editable) : ?>
<div class="box">
<input type="submit" class="add-form" value="Add" form="invoiceElements">
<input type="submit" class="add-form" value="<?= $this->getHtml('Add', '0', '0'); ?>" form="invoiceElements">
</div>
<?php endif; ?>
</div>
@ -356,9 +409,10 @@ echo $this->data['nav']->render(); ?>
<div class="tab col-simple">
<div>
<div class="col-xs-12 col-sm-3 box">
<select id="iBillPreviewType" name="bill_preview_type">>
<select id="iBillPreviewType" name="bill_preview_type"
data-action='[{"listener": "change", "action": [{"key": 1, "type": "dom.reload", "src": "iPreviewBill"}]}]'>
<?php foreach ($billTypes as $type) : ?>
<option value="<?= $type->id; ?>"><?= $this->printHtml($type->getL11n()); ?>
<option value="<?= $type->id; ?>"<?= $type->id === $bill->type->id ? ' selected' : ''; ?>><?= $this->printHtml($type->getL11n()); ?>
<?php endforeach; ?>
</select>
</div>
@ -368,12 +422,14 @@ echo $this->data['nav']->render(); ?>
<div class="col-xs-12 col-simple">
<section id="mediaFile" class="portlet col-simple">
<div class="portlet-body col-simple">
<iframe class="col-simple" id="iHelperFrame" src="" loading="lazy" allowfullscreen></iframe>
<iframe class="col-simple" id="iPreviewBill" data-src="Resources/mozilla/Pdf/web/viewer.html?file=<?= \urlencode(UriFactory::build('{/api}bill/render/preview?bill=' . $bill->id) . '&bill_type='); ?>{#iBillPreviewType}" loading="lazy" allowfullscreen></iframe>
</div>
</section>
</div>
</div>
</div>
<?php if (!$isNew) : ?>
<input type="radio" id="c-tab-4" name="tabular-2">
<div class="tab col-simple">
<div class="col-simple">
@ -386,6 +442,9 @@ echo $this->data['nav']->render(); ?>
</div>
</div>
</div>
<?php endif; ?>
<!--
<input type="radio" id="c-tab-5" name="tabular-2">
<div class="tab">
<div class="row">
@ -465,9 +524,9 @@ echo $this->data['nav']->render(); ?>
<template class="oms-payment-add">
<tr data-id="">
<td><?php if ($editable) : ?>
<i class="fa fa-chevron-up order-up"></i>
<i class="fa fa-chevron-down order-down"></i>
<i class="fa fa-times btn remove-form"></i>
<i class="g-icon order-up">expand_less</i>
<i class="g-icon order-down">expand_more</i>
<i class="g-icon btn remove-form">close</i>
<?php endif; ?>
<td><input type="datetime-local" autocomplete="off" required>
<td><input type="number" value="" autocomplete="off" required>
@ -478,86 +537,60 @@ echo $this->data['nav']->render(); ?>
<?php if ($editable) : ?>
<div class="box">
<input type="submit" class="add-form" value="Add" form="paymentPlan">
<input type="submit" class="add-payment-form" value="<?= $this->getHtml('Add', '0', '0'); ?>" form="paymentPlan">
</div>
<?php endif; ?>
</div>
</div>
</div>
-->
<input type="radio" id="c-tab-6" name="tabular-2">
<div class="tab">
<div class="row">
<div class="col-xs-12 col-md-6 col-lg-4">
<section class="portlet">
<div class="portlet-head"><?= $this->getHtml('Media'); ?></div>
<div class="portlet-body">
<form>
<div class="form-group">
<label for="iMedia"><?= $this->getHtml('Media'); ?></label>
<div class="ipt-first">
<input type="text" id="iMedia" placeholder="&#xf15b; File">
</div>
<div class="ipt-second"><button><?= $this->getHtml('Select'); ?></button></div>
</div>
<div class="form-group">
<label for="iUpload"><?= $this->getHtml('Upload'); ?></label>
<input type="file" id="iUpload" form="fTask"><input form="fTask" type="hidden" name="type">
</div>
</form>
</div>
</section>
</div>
<div class="col-xs-12 col-md-6 col-lg-8">
<?= $this->getData('medialist')?->render($media); ?>
</div>
</div>
<div class="tab col-simple">
<?= $this->data['media-upload']->render('bill-file', 'files', '', $media); ?>
</div>
<?php if (!$isNew && !empty($bill)) : ?>
<input type="radio" id="c-tab-7" name="tabular-2">
<div class="tab">
<?php
$footerView = new \phpOMS\Views\PaginationView($this->l11nManager, $this->request, $this->response);
$footerView->setTemplate('/Web/Templates/Lists/Footer/PaginationBig');
$footerView->setPages(20);
$footerView->setPage(1);
?>
<div class="row">
<div class="col-xs-12">
<div class="portlet">
<div class="portlet-head"><?= $this->getHtml('Logs'); ?><i class="lni lni-download download btn end-xs"></i></div>
<table class="default">
<div class="portlet-head"><?= $this->getHtml('Logs'); ?><i class="g-icon download btn end-xs">download</i></div>
<table class="default sticky">
<thead>
<tr>
<td><?= $this->getHtml('ID', '0', '0'); ?>
<td><?= $this->getHtml('Trigger', 'Auditor', 'Backend'); ?>
<td><?= $this->getHtml('Action', 'Auditor', 'Backend'); ?>
<td class="wf-100"><?= $this->getHtml('Trigger', 'Auditor', 'Backend'); ?>
<td><?= $this->getHtml('CreatedBy', 'Auditor', 'Backend'); ?>
<td><?= $this->getHtml('CreatedAt', 'Auditor', 'Backend'); ?>
<tbody>
<?php
foreach ($logs as $audit) :
$url = UriFactory::build('{/base}/admin/audit/single?id=' . $audit->id);
$url = UriFactory::build('{/base}/admin/audit/view?id=' . $audit->id);
?>
<tr data-href="<?= $url; ?>">
<td><a href="<?= $url; ?>"><?= $audit->id; ?></a>
<td><a href="<?= $url; ?>"><?= $audit->trigger; ?></a>
<td><?php if ($audit->old === null) : echo $this->getHtml('CREATE', 'Auditor', 'Backend'); ?>
<?php elseif ($audit->old !== null && $audit->new !== null) : echo $this->getHtml('UPDATE', 'Auditor', 'Backend'); ?>
<?php elseif ($audit->new === null) : echo $this->getHtml('DELETE', 'Auditor', 'Backend'); ?>
<?php else : echo $this->getHtml('UNKNOWN', 'Auditor', 'Backend'); ?>
<?php endif; ?>
<td><a href="<?= $url; ?>"><?= $audit->trigger; ?></a>
<td><a class="content"
href="<?= UriFactory::build('{/base}/admin/account/settings?id=' . $audit->createdBy->id); ?>"><?= $this->printHtml(
$this->renderUserName('%3$s %2$s %1$s', [$audit->createdBy->name1, $audit->createdBy->name2, $audit->createdBy->name3, $audit->createdBy->login])
); ?></a>
<td><a href="<?= $url; ?>"><?= $audit->createdAt->format('Y-m-d'); ?></a>
<td><a href="<?= $url; ?>"><?= $audit->createdAt->format('Y-m-d H:i'); ?></a>
<?php endforeach; ?>
</table>
</div>
</div>
</div>
</div>
<?php endif; ?>
</div>
</div>

View File

@ -0,0 +1,71 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\ItemManagement
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
use phpOMS\Uri\UriFactory;
/** @var \phpOMS\Views\View $this */
$types = $this->data['types'];
echo $this->data['nav']->render(); ?>
<div class="row">
<div class="col-xs-12">
<section class="portlet">
<div class="portlet-head"><?= $this->getHtml('PaymentTerms'); ?><i class="g-icon download btn end-xs">download</i></div>
<div class="slider">
<table id="iContractTypeList" class="default sticky">
<thead>
<tr>
<td><?= $this->getHtml('ID', '0', '0'); ?>
<label for="iContractTypeList-sort-1">
<input type="radio" name="iContractTypeList-sort" id="iContractTypeList-sort-1">
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="iContractTypeList-sort-2">
<input type="radio" name="iContractTypeList-sort" id="iContractTypeList-sort-2">
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter g-icon">filter_alt</i>
</label>
<td class="wf-100"><?= $this->getHtml('Name'); ?>
<label for="iContractTypeList-sort-2">
<input type="radio" name="iContractTypeList-sort" id="iContractTypeList-sort-2">
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="iContractTypeList-sort-3">
<input type="radio" name="iContractTypeList-sort" id="iContractTypeList-sort-3">
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter g-icon">filter_alt</i>
</label>
<tbody>
<?php
$count = 0;
foreach ($types as $key => $value) : ++$count;
$url = UriFactory::build('{/base}/bill/payment/view?{?}&id=' . $value->id);
?>
<tr data-href="<?= $url; ?>">
<td><a href="<?= $url; ?>"><?= $value->id; ?></a>
<td><a href="<?= $url; ?>"><?= $this->printHtml($value->getL11n()); ?></a>
<?php endforeach; ?>
<?php if ($count === 0) : ?>
<tr><td colspan="2" class="empty"><?= $this->getHtml('Empty', '0', '0'); ?>
<?php endif; ?>
</table>
</div>
</section>
</div>
</div>

View File

@ -0,0 +1,53 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\Billing
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
use phpOMS\Uri\UriFactory;
/** @var \phpOMS\Localization\BaseStringL11nType */
$type = $this->data['type'];
/** @var \phpOMS\Views\View $this */
echo $this->data['nav']->render(); ?>
<div class="row">
<div class="col-xs-12 col-md-6">
<div class="portlet">
<form id="paymentForm" method="POST" action="<?= UriFactory::build('{/api}bill/payment'); ?>"
data-ui-container="#paymentTable tbody"
data-add-form="paymentForm"
data-add-tpl="#paymentTable tbody .oms-add-tpl-payment">
<div class="portlet-head"><?= $this->getHtml('PaymentTerm'); ?></div>
<div class="portlet-body">
<div class="form-group">
<label for="iName"><?= $this->getHtml('Name'); ?></label>
<input type="text" name="code" id="iName" placeholder="" value="<?= $this->printHtml($type->title); ?>">
</div>
</div>
<div class="portlet-foot">
<input type="hidden" name="id" value="<?= $type->id; ?>">
<input id="iSubmit" name="submit" type="submit" value="<?= $this->getHtml('Save', '0', '0'); ?>">
</div>
</form>
</div>
</div>
</div>
<div class="row">
<?= $this->data['l11nView']->render(
$this->data['l11nValues'],
[],
'{/api}bill/payment/l11n'
);
?>
</div>

View File

@ -21,7 +21,7 @@ echo $this->data['nav']->render(); ?>
<div class="row">
<div class="col-xs-12">
<div class="portlet">
<div class="portlet-head"><?= $this->getHtml('Bills'); ?><i class="lni lni-download download btn end-xs"></i></div>
<div class="portlet-head"><?= $this->getHtml('Bills'); ?><i class="g-icon download btn end-xs">download</i></div>
<div class="slider">
<table id="billList" class="default sticky">
<thead>
@ -33,122 +33,134 @@ echo $this->data['nav']->render(); ?>
<td><?= $this->getHtml('ID', '0', '0'); ?>
<label for="billList-sort-1">
<input type="radio" name="billList-sort" id="billList-sort-1">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-2">
<input type="radio" name="billList-sort" id="billList-sort-2">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td><?= $this->getHtml('External'); ?>
<label for="billList-sort-1">
<input type="radio" name="billList-sort" id="billList-sort-1">
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-2">
<input type="radio" name="billList-sort" id="billList-sort-2">
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter g-icon">filter_alt</i>
</label>
<td><?= $this->getHtml('Type'); ?>
<label for="billList-sort-3">
<input type="radio" name="billList-sort" id="billList-sort-3">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-4">
<input type="radio" name="billList-sort" id="billList-sort-4">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td><?= $this->getHtml('SupplierID'); ?>
<label for="billList-sort-5">
<input type="radio" name="billList-sort" id="billList-sort-5">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-6">
<input type="radio" name="billList-sort" id="billList-sort-6">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td class="wf-100"><?= $this->getHtml('Supplier'); ?>
<label for="billList-sort-7">
<input type="radio" name="billList-sort" id="billList-sort-7">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-8">
<input type="radio" name="billList-sort" id="billList-sort-8">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td class="wf-100"><?= $this->getHtml('Address'); ?>
<label for="billList-sort-9">
<input type="radio" name="billList-sort" id="billList-sort-9">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-10">
<input type="radio" name="billList-sort" id="billList-sort-10">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td class="wf-100"><?= $this->getHtml('Postal'); ?>
<label for="billList-sort-11">
<input type="radio" name="billList-sort" id="billList-sort-11">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-12">
<input type="radio" name="billList-sort" id="billList-sort-12">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td class="wf-100"><?= $this->getHtml('City'); ?>
<label for="billList-sort-13">
<input type="radio" name="billList-sort" id="billList-sort-13">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-14">
<input type="radio" name="billList-sort" id="billList-sort-14">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td class="wf-100"><?= $this->getHtml('Country'); ?>
<label for="billList-sort-15">
<input type="radio" name="billList-sort" id="billList-sort-15">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-16">
<input type="radio" name="billList-sort" id="billList-sort-16">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td><?= $this->getHtml('Net'); ?>
<label for="billList-sort-7">
<input type="radio" name="billList-sort" id="billList-sort-7">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-18">
<input type="radio" name="billList-sort" id="billList-sort-18">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td><?= $this->getHtml('Created'); ?>
<label for="billList-sort-23">
<input type="radio" name="billList-sort" id="billList-sort-23">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-24">
<input type="radio" name="billList-sort" id="billList-sort-24">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<tbody>
<?php $count = 0;
@ -162,15 +174,16 @@ echo $this->data['nav']->render(); ?>
<span class="checkmark"></span>
</label>
<td><a href="<?= $url; ?>"><?= $value->getNumber(); ?></a>
<td><a href="<?= $url; ?>"><?= $value->external; ?></a>
<td><a href="<?= $url; ?>"><?= $value->type->getL11n(); ?></a>
<td><a class="content" href="<?= $supplier = UriFactory::build('purchase/supplier/profile?{?}&id=' . $value->supplier->id); ?>"><?= $value->supplier->number; ?></a>
<td><a class="content" href="<?= $supplier = UriFactory::build('purchase/supplier/view?{?}&id=' . $value->supplier->id); ?>"><?= $value->supplier->number; ?></a>
<td><a class="content" href="<?= $supplier; ?>"><?= $this->printHtml($value->billTo); ?></a>
<td><a href="<?= $url;
?>"><?= $value->billAddress; ?></a>
<td><a href="<?= $url; ?>"><?= $value->billZip; ?></a>
<td><a href="<?= $url; ?>"><?= $value->billCity; ?></a>
<td><a href="<?= $url; ?>"><?= $value->billCountry; ?></a>
<td><a href="<?= $url; ?>"><?= $this->getCurrency($value->netSales); ?></a>
<td><a href="<?= $url; ?>"><?= $value->netSales->getAmount(); ?></a>
<td><a href="<?= $url; ?>"><?= $value->createdAt->format('Y-m-d'); ?></a>
<?php endforeach; ?>
<?php if ($count === 0) : ?>

View File

@ -12,11 +12,17 @@
*/
declare(strict_types=1);
use phpOMS\System\File\FileUtils;
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
@ -24,26 +30,59 @@ include __DIR__ . '/../../../Media/Theme/Backend/template-functions.php';
/** @var \Modules\Billing\Models\Bill $bill */
$bill = $this->data['bill'];
$elements = $bill->getElements();
$elements = $bill->elements;
$previewType = $this->data['previewType'];
$originalType = $this->data['originalType'];
$billPdf = $bill->getFileByType($previewType);
$original = $bill->getFileByType($originalType);
$media = $bill->files;
$billTypes = $this->data['billtypes'] ?? [];
$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(); ?>
<?php if (!$bill->isValid()) : ?>
<div class="row">
<div class="col-xs-12">
<section class="portlet hl-1">
<article class="hl-1">
<ul>
<?php if (!$bill->areElementsValid()) : ?>
<li><?= $this->getHtml('E_bill_items'); ?></li>
<?php endif; ?>
<?php if (!$bill->validateTaxAmountElements()) : ?>
<li><?= $this->getHtml('E_bill_taxes'); ?></li>
<?php endif; ?>
<?php if (!$bill->validateNetElements()) : ?>
<li><?= $this->getHtml('E_bill_net'); ?></li>
<?php endif; ?>
<?php if (!$bill->validateGrossElements()) : ?>
<li><?= $this->getHtml('E_bill_gross'); ?></li>
<?php endif; ?>
<?php if (!$bill->validatePriceQuantityElements()) : ?>
<li><?= $this->getHtml('E_bill_unit'); ?></li>
<?php endif; ?>
</ul>
</article>
</section>
</div>
</div>
<?php endif; ?>
<div class="tabview tab-2 col-simple">
<div class="box">
<ul class="tab-links">
<li><label for="c-tab-1"><?= $this->getHtml('Invoice'); ?></label></li>
<li><label for="c-tab-2"><?= $this->getHtml('Items'); ?></label></li>
<li><label for="c-tab-3"><?= $this->getHtml('Preview'); ?></label></li>
<li><label for="c-tab-4"><?= $this->getHtml('Original'); ?></label></li>
<li><label for="c-tab-5"><?= $this->getHtml('Payment'); ?></label></li>
<li><label for="c-tab-6"><?= $this->getHtml('Media'); ?></label></li>
<li><label for="c-tab-7"><?= $this->getHtml('Logs'); ?></label></li>
<li><label for="c-tab-1"><?= $this->getHtml('Invoice'); ?></label>
<li><label for="c-tab-2"><?= $this->getHtml('Items'); ?></label>
<li><label for="c-tab-3"><?= $this->getHtml('Internal'); ?></label>
<?php if (!$isNew) : ?><li><label for="c-tab-4"><?= $this->getHtml('Archive'); ?></label><?php endif; ?>
<!--<li><label for="c-tab-5"><?= $this->getHtml('Payment'); ?></label>-->
<li><label for="c-tab-6"><?= $this->getHtml('Files'); ?></label>
<?php if (!$isNew && !empty($logs)) : ?><li><label for="c-tab-7"><?= $this->getHtml('Logs'); ?></label><?php endif; ?>
</ul>
</div>
<div class="tab-content col-simple">
@ -55,61 +94,148 @@ echo $this->data['nav']->render(); ?>
<form>
<div class="portlet-head"><?= $this->getHtml('Invoice'); ?></div>
<div class="portlet-body">
<table class="layout wf-100">
<tr><td><label for="iSource"><?= $this->getHtml('Source'); ?></label>
<tr><td><span class="input"><button type="button" formaction=""><i class="fa fa-book"></i></button><input type="text" id="iSource" name="source"></span>
<tr><td><label for="iType"><?= $this->getHtml('Type'); ?></label>
<tr><td><select id="iType" name="type">
<option><?= $this->getHtml('Invoice'); ?>
<option><?= $this->getHtml('Offer'); ?>
<option><?= $this->getHtml('Confirmation'); ?>
<option><?= $this->getHtml('DeliveryNote'); ?>
<option><?= $this->getHtml('CreditNote'); ?>
</select>
<tr><td><label for="iClient"><?= $this->getHtml('Client'); ?></label>
<tr><td><span class="input"><button type="button" formaction=""><i class="fa fa-book"></i></button><input type="text" id="iClient" name="client"></span>
<tr><td><label for="iDelivery"><?= $this->getHtml('Delivery'); ?></label>
<tr><td><input type="datetime-local" id="iDelivery" name="delivery">
<tr><td><label for="iDue"><?= $this->getHtml('Due'); ?></label>
<tr><td><input type="datetime-local" id="iDue" name="due">
<tr><td><label for="iFreightage"><?= $this->getHtml('Freightage'); ?></label>
<tr><td><input type="number" id="iFreightage" name="freightage">
<tr><td><label for="iShipment"><?= $this->getHtml('Shipment'); ?></label>
<tr><td><select id="iShipment" name="shipment">
<option>
</select>
<tr><td><label for="iTermsOfDelivery"><?= $this->getHtml('TermsOfDelivery'); ?></label>
<tr><td><select id="iTermsOfDelivery" name="termsofdelivery">
<option>
</select>
</table>
<div class="form-group">
<label for="iLanguage"><?= $this->getHtml('Language'); ?></label>
<select id="iLanguage" name="bill_language"<?= $disabled; ?>>
<?php foreach ($languages as $code => $language) : $code = \strtolower(\substr($code, 1)); ?>
<option value="<?= $this->printHtml($code); ?>"<?= $code === $bill->language ? ' selected' : ''; ?>><?= $this->printHtml($language); ?>
<?php endforeach; ?>
</select>
</div>
<div class="form-group">
<label for="iCurrency"><?= $this->getHtml('Currency'); ?></label>
<select id="iCurrency" name="bill_currency"<?= $disabled; ?>>
<?php foreach ($currencies as $code => $currency) : $code = \substr($code, 1); ?>
<option value="<?= $this->printHtml($code); ?>"<?= $code === $bill->currency ? ' selected' : ''; ?>><?= $this->printHtml($currency); ?>
<?php endforeach; ?>
</select>
</div>
<div class="form-group">
<label for="iSource"><?= $this->getHtml('Source'); ?></label>
<span class="input">
<button type="button" formaction="">
<i class="g-icon">book</i>
</button>
<input type="text" id="iSource" name="bill_source"<?= $disabled; ?>>
</span>
</div>
<div class="form-group">
<label for="iBillType"><?= $this->getHtml('Type'); ?></label>
<select id="iBillType" name="bill_type"<?= $disabled; ?>>
<?php foreach ($billTypes as $type) : ?>
<option value="<?= $type->id; ?>"<?= $type->id === $bill->type->id ? ' selected' : ''; ?>><?= $this->printHtml($type->getL11n()); ?>
<?php endforeach; ?>
</select>
</div>
<div class="form-group">
<label for="iClient"><?= $this->getHtml('Supplier'); ?></label>
<div class="ipt-wrap">
<div class="ipt-first">
<span class="input">
<button type="button" formaction="">
<i class="g-icon">book</i>
</button>
<input type="text" id="iClient" name="bill_client" value="<?= $bill->client?->number ?? $bill->supplier?->number; ?>"<?= $disabled; ?>>
</span>
</div>
<?php if (($bill->client?->id ?? 0) > 0) : ?>
<div class="ipt-second">
<a class="button" href="<?= UriFactory::build('{/base}/sales/client/view?id=' . $bill->client->id); ?>"><?= $this->getHtml('Client'); ?></a>
</div>
<?php endif; ?>
</div>
</div>
<div class="form-group">
<label for="iInvoiceDate"><?= $this->getHtml('Invoice'); ?></label>
<input type="datetime-local" id="iInvoiceDate" name="bill_invoice_date"
value="<?= $bill->createdAt->format('Y-m-d\TH:i'); ?>"<?= $disabled; ?>>
</div>
<div class="form-group">
<label for="iDeliveryDate"><?= $this->getHtml('Delivery'); ?></label>
<input type="datetime-local" id="iDeliveryDate" name="bill_delivery_date"
value="<?= $bill->createdAt->format('Y-m-d\TH:i'); ?>"<?= $disabled; ?>>
</div>
<div class="form-group">
<label for="iDueDate"><?= $this->getHtml('Due'); ?></label>
<input type="datetime-local" id="iDueDate" name="bill_due"
value="<?= (new \DateTime('now'))->format('Y-m-d\TH:i'); ?>"<?= $disabled; ?>>
</div>
<div class="form-group">
<label for="iShipment"><?= $this->getHtml('Shipment'); ?></label>
<select id="iShipment" name="bill_shipment_type"<?= $disabled; ?>>
<option>
</select>
</div>
<div class="form-group">
<label for="iTermsOfDelivery"><?= $this->getHtml('TermsOfDelivery'); ?></label>
<select id="iTermsOfDelivery" name="bill_termsofdelivery"<?= $disabled; ?>>
<option>
</select>
</div>
</div>
<div class="portlet-foot"><input type="submit" value="<?= $this->getHtml('Create', '0', '0'); ?>" name="create-bill"></div>
<?php if ($editable) : ?>
<div class="portlet-foot">
<input type="submit" value="<?= $this->getHtml('Create', '0', '0'); ?>" name="create-invoice">
</div>
<?php endif; ?>
</form>
</section>
</div>
<div class="col-xs-12 col-md-6 col-lg-4">
<section class="portlet">
<div class="portlet-head"><?= $this->getHtml('Invoice'); ?></div>
<div class="portlet-head"><?= $this->getHtml('Billing'); ?></div>
<div class="portlet-body">
<form>
<table class="layout wf-100">
<tr><td><label for="iAddressS"><?= $this->getHtml('Addresses'); ?></label>
<tr><td><select id="iAddressS" name="addressS">
<option>
</select>
<tr><td><label for="iIRecipient"><?= $this->getHtml('Recipient'); ?></label>
<tr><td><input type="text" id="iIRecipient" name="irecipient">
<tr><td><label for="iAddress"><?= $this->getHtml('Address'); ?></label>
<tr><td><input type="text" id="iAddress" name="address">
<tr><td><label for="iZip"><?= $this->getHtml('Zip'); ?></label>
<tr><td><input type="text" id="iZip" name="zip">
<tr><td><label for="iCity"><?= $this->getHtml('City'); ?></label>
<tr><td><input type="text" id="iCity" name="city">
<tr><td><label for="iCountry"><?= $this->getHtml('Country'); ?></label>
<tr><td><input type="text" id="iCountry" name="country">
</table>
<div class="form-group">
<label for="iAddressListBill"><?= $this->getHtml('Addresses'); ?></label>
<select id="iAddressListBill" name="bill_address_bill_list"<?= $disabled; ?>>
<option>
</select>
</div>
<div class="form-group">
<label for="iRecipientBill"><?= $this->getHtml('Recipient'); ?></label>
<input type="text" id="iRecipientBill" name="bill_recipient_bill" value="<?= $this->printHtml($bill->billTo); ?>"<?= $disabled; ?>>
</div>
<div class="form-group">
<label for="iAddressBill"><?= $this->getHtml('Address'); ?></label>
<input type="text" id="iAddressBill" name="bill_address_bill" value="<?= $this->printHtml($bill->billAddress); ?>"<?= $disabled; ?>>
</div>
<div class="form-group">
<label for="iZipBill"><?= $this->getHtml('Zip'); ?></label>
<input type="text" id="iZipBill" name="bill_address_bill" value="<?= $this->printHtml($bill->billZip); ?>"<?= $disabled; ?>>
</div>
<div class="form-group">
<label for="iCityBill"><?= $this->getHtml('City'); ?></label>
<input type="text" id="iCityBill" name="bill_city_bill" value="<?= $this->printHtml($bill->billCity); ?>"<?= $disabled; ?>>
</div>
<div class="form-group">
<label for="iCountryBill"><?= $this->getHtml('Country'); ?></label>
<select id="iCountryBill" name="bill_country_bill"<?= $disabled; ?>>
<?php foreach ($countryCodes as $code3 => $code2) : ?>
<option value="<?= $this->printHtml($code2); ?>"<?= $code2 === $bill->billCountry ? ' selected' : ''; ?>><?= $this->printHtml($countries[$code3]); ?>
<?php endforeach; ?>
</select>
</div>
<div class="form-group">
<label for="iEmailBill"><?= $this->getHtml('Email'); ?></label>
<input type="text" id="iEmailBill" name="bill_email_bill" value="<?= $this->printHtml($bill->billEmail); ?>"<?= $disabled; ?>>
</div>
</form>
</div>
</section>
@ -120,22 +246,42 @@ echo $this->data['nav']->render(); ?>
<div class="portlet-head"><?= $this->getHtml('Delivery'); ?></div>
<div class="portlet-body">
<form>
<table class="layout wf-100">
<tr><td><label for="iAddressS"><?= $this->getHtml('Addresses'); ?></label>
<tr><td><select id="iAddressS" name="addressS">
<option>
</select>
<tr><td><label for="iDRecipient"><?= $this->getHtml('Recipient'); ?></label>
<tr><td><input type="text" id="iDRecipient" name="drecipient">
<tr><td><label for="iAddress"><?= $this->getHtml('Address'); ?></label>
<tr><td><input type="text" id="iAddress" name="address">
<tr><td><label for="iZip"><?= $this->getHtml('Zip'); ?></label>
<tr><td><input type="text" id="iZip" name="zip">
<tr><td><label for="iCity"><?= $this->getHtml('City'); ?></label>
<tr><td><input type="text" id="iCity" name="city">
<tr><td><label for="iCountry"><?= $this->getHtml('Country'); ?></label>
<tr><td><input type="text" id="iCountry" name="country">
</table>
<div class="form-group">
<label for="iAddressListDelivery"><?= $this->getHtml('Addresses'); ?></label>
<select id="iAddressListDelivery" name="bill_address_delivery_list"<?= $disabled; ?>>
<option>
</select>
</div>
<div class="form-group">
<label for="iRecipientDelivery"><?= $this->getHtml('Recipient'); ?></label>
<input type="text" id="iRecipientDelivery" name="bill_recipient_delivery" value="<?= $this->printHtml($bill->shipTo); ?>"<?= $disabled; ?>>
</div>
<div class="form-group">
<label for="iAddressDelivery"><?= $this->getHtml('Address'); ?></label>
<input type="text" id="iAddressDelivery" name="bill_address_delivery" value="<?= $this->printHtml($bill->shipAddress); ?>"<?= $disabled; ?>>
</div>
<div class="form-group">
<label for="iZipDelivery"><?= $this->getHtml('Zip'); ?></label>
<input type="text" id="iZipDelivery" name="bill_zip_delivery" value="<?= $this->printHtml($bill->shipZip); ?>"<?= $disabled; ?>>
</div>
<div class="form-group">
<label for="iCityDelivery"><?= $this->getHtml('City'); ?></label>
<input type="text" id="iCityDelivery" name="bill_city_delivery" value="<?= $this->printHtml($bill->shipCity); ?>"<?= $disabled; ?>>
</div>
<div class="form-group">
<label for="iCountryDelivery"><?= $this->getHtml('Country'); ?></label>
<select id="iCountryDelivery" name="bill_country_delivery"<?= $disabled; ?>>
<option value="" <?= $bill->shipTo === '' ? 'selected ' : ''; ?>><?= $this->getHtml('Select', '0', '0'); ?>
<?php foreach ($countryCodes as $code3 => $code2) : ?>
<option value="<?= $this->printHtml($code2); ?>"<?= $code2 === $bill->shipCountry ? ' selected' : ''; ?>><?= $this->printHtml($countries[$code3]); ?>
<?php endforeach; ?>
</select>
</div>
</form>
</div>
</section>
@ -146,208 +292,322 @@ echo $this->data['nav']->render(); ?>
<div class="tab">
<div class="row">
<div class="col-xs-12">
<div class="portlet">
<div class="portlet-head"><?= $this->getHtml('Invoice'); ?><i class="lni lni-download download btn end-xs"></i></div>
<section class="portlet">
<div class="portlet-head"><?= $this->getHtml('Invoice'); ?><i class="g-icon download btn end-xs">download</i></div>
<div class="slider">
<table class="default" id="invoice-item-list">
<table
id="invoiceElements"
class="default sticky"
data-action="<?= \phpOMS\Uri\UriFactory::build('{/api}billing/bill/element?{?}&csrf={$CSRF}'); ?>"
data-tag="form"
data-ui-container="tbody"
data-ui-element="tr"
data-on-change="1"
data-add-tpl=".oms-invoice-add">
<thead>
<tr>
<td>
<td><?= $this->getHtml('Item'); ?>
<td class="wf-100"><?= $this->getHtml('Name'); ?>
<td><?= $this->getHtml('Quantity'); ?>
<td><?= $this->getHtml('Price'); ?>
<td><?= $this->getHtml('Discount'); ?>
<td><?= $this->getHtml('DiscountP'); ?>
<td><?= $this->getHtml('Bonus'); ?>
<td><?= $this->getHtml('Tax'); ?>
<td style="min-width:150px"><?= $this->getHtml('Item'); ?>
<td class="wf-100" style="min-width:150px"><?= $this->getHtml('Name'); ?>
<td style="min-width:75px"><?= $this->getHtml('Quantity'); ?>
<td style="min-width:90px"><?= $this->getHtml('Discount'); ?>
<td style="min-width:90px"><?= $this->getHtml('DiscountP'); ?>
<td style="min-width:75px"><?= $this->getHtml('Bonus'); ?>
<td style="min-width:90px"><?= $this->getHtml('Price'); ?>
<td style="min-width:75px"><?= $this->getHtml('TaxP'); ?>
<td><?= $this->getHtml('Net'); ?>
<tbody>
<?php foreach ($elements as $element) : ?>
<tr>
<td><i class="fa fa-plus add"></i> <i class="fa fa-chevron-up order-up"></i> <i class="fa fa-chevron-down order-down"></i>
<td><span class="input"><button type="button" formaction=""><i class="fa fa-book"></i></button><input name="" type="text" value="<?= $element->itemNumber; ?>" required></span>
<td><textarea required><?= $element->itemName; ?></textarea>
<td><input name="" type="number" min="0" value="<?= $element->quantity; ?>" required>
<td><input name="" type="text" value="<?= $this->getCurrency($element->singleSalesPriceNet); ?>">
<td><input name="" type="number" min="0">
<td><input name="" type="number" min="0" max="100" step="any">
<td><input name="" type="number" min="0" step="any">
<td><input name="" type="number" min="0" step="any">
<td><?= $this->getCurrency($element->totalSalesPriceNet); ?>
<?php endforeach; ?>
<tr>
<td><i class="fa fa-plus"></i> <i class="fa fa-chevron-up order-up"></i> <i class="fa fa-chevron-down order-down"></i>
<td><span class="input"><button type="button" formaction=""><i class="fa fa-book"></i></button><input name="" type="text" required></span>
<td><textarea required></textarea>
<td><input name="" type="number" min="0" value="0" required>
<td><input name="" type="text">
<td><input name="" type="number" min="0">
<td><input name="" type="number" min="0" max="100" step="any">
<td><input name="" type="number" min="0" step="any">
<td><input name="" type="number" min="0" step="any">
<td>
<td><?= $this->getHtml('Margin'); ?>
<tbody class="oms-ordercontainer">
<?php if ($editable) : ?>
<template class="oms-invoice-add">
<tr data-id="">
<td>
<i class="g-icon order-up">expand_less</i>
<i class="g-icon order-down">expand_more</i>
<i class="g-icon btn remove-form">close</i>
<td><span class="input">
<button type="button" formaction="">
<label><i class="g-icon">book</i></label>
</button><input name="item_number" type="text" autocomplete="off"></span>
<td><textarea name="item_description" autocomplete="off"></textarea>
<td><input name="item_quantity" type="number" step="any" value="" autocomplete="off">
<td><input name="item_discountp" type="number" step="any" value="" autocomplete="off">
<td><input name="item_discountr" type="number" min="-100" max="100" step="0.01" value="" autocomplete="off">
<td><input name="item_bonus" type="number" step="any" value="" autocomplete="off">
<td><input name="item_price" type="number" step="any" value="" autocomplete="off">
<td><input name="item_taxr" type="number" step="any" value="" autocomplete="off">
<td>
<td>
</tr>
</template>
<?php endif; ?>
<?php foreach ($elements as $element) : ?>
<tr>
<td><?php if ($editable) : ?>
<i class="g-icon order-up">expand_less</i>
<i class="g-icon order-down">expand_more</i>
<i class="g-icon btn remove-form">close</i>
<?php endif; ?>
<td><span class="input">
<button type="button" formaction="">
<i class="g-icon">book</i>
</button><input name="item_number" autocomplete="off" type="text" value="<?= $element->itemNumber; ?>"<?= $disabled; ?>></span>
<td><textarea name="item_description" autocomplete="off"<?= $disabled; ?>><?= $element->itemName; ?></textarea>
<td><input name="item_quantity" autocomplete="off" type="number" step="any" value="<?= $element->quantity->sub($element->discountQ)->getAmount($element->container->quantityDecimals); ?>"<?= $disabled; ?>>
<td><input name="item_discountp" autocomplete="off" type="number" step="any" value="<?= $element->singleDiscountP->getAmount(); ?>"<?= $disabled; ?>>
<td><input name="item_discountr" autocomplete="off" type="number" step="any" value="<?= $element->singleDiscountR->getAmount(); ?>"<?= $disabled; ?>>
<td><input name="item_bonus" autocomplete="off" type="number" min="-100" max="100" step="0.01" value="<?= $element->discountQ->getAmount($element->container->quantityDecimals); ?>"<?= $disabled; ?>>
<td><input name="item_price" autocomplete="off" type="number" step="any" value="<?= $element->singleSalesPriceNet->getFloat(); ?>"<?= $disabled; ?>>
<td><input name="item_taxr" autocomplete="off" type="number" step="any" value="<?= $element->taxR->getAmount(); ?>"<?= $disabled; ?>>
<td><?= $this->getCurrency($element->totalSalesPriceNet, symbol: ''); ?>
<td><?= \number_format($element->totalSalesPriceNet->value === 0 ? 0 : (1 - $element->totalPurchasePriceNet->value / $element->totalSalesPriceNet->value) * 100, 2); ?>%
<?php endforeach; ?>
<?php if ($editable) : ?>
<tr data-id="0">
<td><i class="g-icon order-up">expand_less</i>
<i class="g-icon order-down">expand_more</i>
<i class="g-icon btn remove-form">close</i>
<td><span class="input">
<button type="button" formaction="">
<i class="g-icon">book</i></button><input name="item_number" type="text" autocomplete="off"></span>
<td><textarea name="item_description" autocomplete="off"></textarea>
<td><input name="item_quantity" type="number" step="any" value="" autocomplete="off">
<td><input name="item_discountp" type="number" step="any" value="" autocomplete="off">
<td><input name="item_discountr" type="number" min="-100" max="100" step="0.01" value="" autocomplete="off">
<td><input name="item_bonus" type="number" step="any" value="" autocomplete="off">
<td><input name="item_price" type="number" step="any" value="" autocomplete="off">
<td><input name="item_taxr" type="number" step="any" value="" autocomplete="off">
<td>
<td>
<?php endif; ?>
<tfoot>
<tr class="hl-2">
<td colspan="3"><?= $this->getHtml('Total'); ?>
<td>
<td><?= $bill->netDiscount->getAmount(2); ?>
<td><?= \number_format($bill->netDiscount->value === 0 ? 0 : ($bill->netDiscount->value / ($bill->netSales->value + $bill->netDiscount->value)) * 100, 2); ?>%
<td>
<td>
<td><?= $bill->taxP->getAmount(2); ?>
<td><?= $bill->netSales->getAmount(2); ?>
<td><?= \number_format($bill->netSales->value === 0 ? 0 : (1 - $bill->netCosts->value / $bill->netSales->value) * 100, 2); ?>%
</table>
</div>
<div class="portlet-foot">
<?= $this->getHtml('Freightage'); ?>: 0.00 -
<?= $this->getHtml('Net'); ?>: <?= $this->getCurrency($bill->netSales); ?> -
<?= $this->getHtml('Tax'); ?>: 0.00 -
<?= $this->getHtml('Total'); ?>: <?= $this->getCurrency($bill->grossSales); ?>
</div>
</section>
<?php if ($editable) : ?>
<div class="box">
<input type="submit" class="add-form" value="<?= $this->getHtml('Add', '0', '0'); ?>" form="invoiceElements">
</div>
<?php endif; ?>
</div>
</div>
</div>
<input type="radio" id="c-tab-3" name="tabular-2">
<div class="tab col-simple">
<div class="row col-simple">
<div>
<div class="col-xs-12 col-sm-3 box">
<select id="iBillPreviewType" name="bill_preview_type"
data-action='[{"listener": "change", "action": [{"key": 1, "type": "dom.reload", "src": "iPreviewBill"}]}]'>
<?php foreach ($billTypes as $type) : ?>
<option value="<?= $type->id; ?>"<?= $type->id === $bill->type->id ? ' selected' : ''; ?>><?= $this->printHtml($type->getL11n()); ?>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="col-simple">
<div class="col-xs-12 col-simple">
<section id="mediaFile" class="portlet col-simple">
<div class="portlet-body col-simple">
<?php if ($billPdf->id > 0) : ?>
<iframe class="col-simple" data-form="iUiSettings" data-name="iframeHelper" id="iHelperFrame" src="<?= UriFactory::build('Resources/mozilla/Pdf/web/viewer.html{?}&file=' . \urlencode(($billPdf->isAbsolute ? '' : '/../../../../') . $billPdf->getPath())); ?>" allowfullscreen></iframe>
<?php endif; ?>
<iframe class="col-simple" id="iPreviewBill" data-src="Resources/mozilla/Pdf/web/viewer.html?file=<?= \urlencode(UriFactory::build('{/api}bill/render/preview?bill=' . $bill->id) . '&bill_type='); ?>{#iBillPreviewType}" loading="lazy" allowfullscreen></iframe>
</div>
</section>
</div>
</div>
</div>
<?php if (!$isNew) : ?>
<input type="radio" id="c-tab-4" name="tabular-2">
<div class="tab col-simple">
<div class="row col-simple">
<?php if ($bill->status === BillStatus::DRAFT
|| $bill->status === BillStatus::UNPARSED
|| $bill->status === BillStatus::ACTIVE
) : ?>
<div>
<div class="col-xs-12 col-sm-3 box">
<form id="iInvoiceRecognition"
action="<?= UriFactory::build('{/api}bill/parse?id=' . $bill->id . '&async=0'); ?>"
method="post"
data-redirect="<?= UriFactory::build('{%}'); ?>">
<input type="submit" value="<?= $this->getHtml('Parse'); ?>">
</form>
</div>
</div>
<?php endif; ?>
<div class="col-simple">
<div class="col-xs-12 col-simple">
<section id="mediaFile" class="portlet col-simple">
<div class="portlet-body col-simple">
<?php if ($original->id > 0) : ?>
<iframe class="col-simple" id="iOriginal" src="<?= UriFactory::build('Resources/mozilla/Pdf/web/viewer.html?file=' . \urlencode(UriFactory::build('{/api}media/export?id=' . $original->id))); ?>" allowfullscreen></iframe>
<?php endif; ?>
<iframe id="iBillArchive"
class="col-simple"
src="<?= UriFactory::build('{/api}media/export') . '?id=' . $archive->id; ?>"
loading="lazy" allowfullscreen></iframe>
</div>
</section>
</div>
</div>
</div>
<?php endif; ?>
<!--
<input type="radio" id="c-tab-5" name="tabular-2">
<div class="tab">
<div class="row">
<div class="col-xs-12 col-md-6 col-lg-4">
<section class="box wf-100">
<header><h1><?= $this->getHtml('Payment'); ?></h1></header>
<div class="inner">
<section class="portlet">
<div class="portlet-head"><?= $this->getHtml('Payment'); ?></div>
<div class="portlet-body">
<form>
<table class="layout wf-100">
<tr><td><label for="iType"><?= $this->getHtml('Type'); ?></label>
<tr><td><select id="iType" name="type">
<option>
</select>
<tr><td><label for="iType"><?= $this->getHtml('Type'); ?></label>
<tr><td><select id="iType" name="type">
<option><?= $this->getHtml('MoneyTransfer'); ?>
<option><?= $this->getHtml('Prepaid'); ?>
<option><?= $this->getHtml('AlreadyPaid'); ?>
<option><?= $this->getHtml('CreditCard'); ?>
<option><?= $this->getHtml('DirectDebit'); ?>
</select>
<tr><td><label for="iDue"><?= $this->getHtml('Due'); ?></label>
<tr><td><input type="datetime-local" id="iDue" name="due">
<tr><td><label for="iDue"><?= $this->getHtml('Due'); ?> - <?= $this->getHtml('Cashback'); ?></label>
<tr><td><input type="datetime-local" id="iDue" name="due">
<tr><td><label for="iCashBack"><?= $this->getHtml('Cashback'); ?></label>
<tr><td><input type="number" id="iCashBack" name="cashback">
<tr><td><label for="iDue"><?= $this->getHtml('Due'); ?> - <?= $this->getHtml('Cashback'); ?> 2</label>
<tr><td><input type="datetime-local" id="iDue" name="due">
<tr><td><label for="iCashBack2"><?= $this->getHtml('Cashback'); ?> 2</label>
<tr><td><input type="number" id="iCashBack2" name="cashback2">
<tr><td><input type="submit" value="<?= $this->getHtml('Create', '0', '0'); ?>" name="create-bill">
</table>
</form>
</div>
</section>
</div>
</div>
</div>
<input type="radio" id="c-tab-6" name="tabular-2">
<div class="tab">
<div class="row">
<div class="col-xs-12 col-md-6 col-lg-4">
<section class="box wf-100">
<header><h1><?= $this->getHtml('Media'); ?></h1></header>
<div class="form-group">
<label for="iPaymentTypeList"><?= $this->getHtml('Types'); ?></label>
<input type="text" id="iPaymentTypeList" name="bill_payment_type_list"<?= $disabled; ?>>
</div>
<div class="inner">
<form>
<table class="layout wf-100">
<tbody>
<tr><td colspan="2"><label for="iMedia"><?= $this->getHtml('Media'); ?></label>
<tr><td><input type="text" id="iMedia" placeholder="&#xf15b; File"><td><button><?= $this->getHtml('Select'); ?></button>
<tr><td colspan="2"><label for="iUpload"><?= $this->getHtml('Upload'); ?></label>
<tr><td><input type="file" id="iUpload" form="fTask"><input form="fTask" type="hidden" name="type"><td>
</table>
<div class="form-group">
<label for="iPaymentType"><?= $this->getHtml('Type'); ?></label>
<select id="iPaymentType" name="bill_payment_type"<?= $disabled; ?>>
<option><?= $this->getHtml('MoneyTransfer'); ?>
<option><?= $this->getHtml('Prepaid'); ?>
<option><?= $this->getHtml('AlreadyPaid'); ?>
<option><?= $this->getHtml('CreditCard'); ?>
<option><?= $this->getHtml('DirectDebit'); ?>
</select>
</div>
<div class="form-group">
<label for="iPaymentDueDate"><?= $this->getHtml('Due'); ?></label>
<input type="datetime-local" id="iPaymentDueDate" name="bill_payment_due_date"<?= $disabled; ?>>
</div>
</div>
<div class="portlet-separator"></div>
<div class="portlet-body">
<div class="form-group">
<label for="iPaymentCashbackDate1"><?= $this->getHtml('Cashback'); ?></label>
<input type="datetime-local" id="iPaymentCashbackDate1" name="bill_payment_cashback_date1"<?= $disabled; ?>>
</div>
<div class="form-group">
<label for="iPaymentCashbackAmount1"><?= $this->getHtml('Cashback'); ?></label>
<input type="number" id="iPaymentCashbackAmount1" name="bill_payment_cashback_amount1"<?= $disabled; ?>>
</div>
</div>
<div class="portlet-separator"></div>
<div class="portlet-body">
<div class="form-group">
<label for="iPaymentCashbackDate2"><?= $this->getHtml('Cashback'); ?></label>
<input type="datetime-local" id="iPaymentCashbackDate2" name="bill_payment_cashback_date2"<?= $disabled; ?>>
</div>
<div class="form-group">
<label for="iPaymentCashbackAmount2"><?= $this->getHtml('Cashback'); ?></label>
<input type="number" id="iPaymentCashbackAmount2" name="bill_payment_cashback_amount2"<?= $disabled; ?>>
</div>
</form>
</div>
</section>
</div>
<div class="col-xs-12 col-md-6 col-lg-8">
<div class="portlet">
<div class="portlet-head"><?= $this->getHtml('Media'); ?><i class="lni lni-download download btn end-xs"></i></div>
<table class="default" id="invoice-item-list">
<section class="portlet">
<div class="portlet-head"><?= $this->getHtml('PaymentPlan'); ?></div>
<table id="paymentPlan"
class="default sticky"
data-tag="form"
data-ui-container="tbody"
data-ui-element="tr"
data-add-tpl=".oms-payment-add">
<thead>
<tr>
<td>
<td>
<td class="wf-100"><?= $this->getHtml('Name'); ?>
<td><?= $this->getHtml('Type'); ?>
<tbody>
<?php foreach ($media as $file) :
$url = $file->extension === 'collection'
? UriFactory::build('{/base}/media/list?path=' . \rtrim($file->getVirtualPath(), '/') . '/' . $file->name)
: UriFactory::build('{/base}/media/single?id=' . $file->id
. '&path={?path}' . (
$file->id === 0
? '/' . $file->name
: ''
)
);
<td class="wf-100"><?= $this->getHtml('Date'); ?>
<td><?= $this->getHtml('Amount'); ?>
<tbody class="oms-ordercontainer">
<template class="oms-payment-add">
<tr data-id="">
<td><?php if ($editable) : ?>
<i class="g-icon order-up">expand_less</i>
<i class="g-icon order-down">expand_more</i>
<i class="g-icon btn remove-form">close</i>
<?php endif; ?>
<td><input type="datetime-local" autocomplete="off" required>
<td><input type="number" value="" autocomplete="off" required>
</tr>
</template>
</table>
</section>
$icon = $fileIconFunction(FileUtils::getExtensionType($file->extension));
<?php if ($editable) : ?>
<div class="box">
<input type="submit" class="add-payment-form" value="<?= $this->getHtml('Add', '0', '0'); ?>" form="paymentPlan">
</div>
<?php endif; ?>
</div>
</div>
</div>
-->
<input type="radio" id="c-tab-6" name="tabular-2">
<div class="tab col-simple">
<?= $this->data['media-upload']->render('bill-file', 'files', '', $bill->files); ?>
</div>
<?php if (!$isNew && !empty($logs)) : ?>
<input type="radio" id="c-tab-7" name="tabular-2">
<div class="tab">
<div class="row">
<div class="col-xs-12">
<div class="portlet">
<div class="portlet-head"><?= $this->getHtml('Logs'); ?><i class="g-icon download btn end-xs">download</i></div>
<table class="default sticky">
<thead>
<tr>
<td><?= $this->getHtml('ID', '0', '0'); ?>
<td><?= $this->getHtml('Action', 'Auditor', 'Backend'); ?>
<td class="wf-100"><?= $this->getHtml('Trigger', 'Auditor', 'Backend'); ?>
<td><?= $this->getHtml('CreatedBy', 'Auditor', 'Backend'); ?>
<td><?= $this->getHtml('CreatedAt', 'Auditor', 'Backend'); ?>
<tbody>
<?php
foreach ($logs as $audit) :
$url = UriFactory::build('{/base}/admin/audit/view?id=' . $audit->id);
?>
<tr data-href="<?= $url; ?>">
<td>
<td data-label="<?= $this->getHtml('Type'); ?>"><a href="<?= $url; ?>"><i class="fa fa-<?= $this->printHtml($icon); ?>"></i></a>
<td><a href="<?= $url; ?>"><?= $file->name; ?></a>
<td><a href="<?= $url; ?>"><?= $file->extension; ?></a>
<td><a href="<?= $url; ?>"><?= $audit->id; ?></a>
<td><?php if ($audit->old === null) : echo $this->getHtml('CREATE', 'Auditor', 'Backend'); ?>
<?php elseif ($audit->old !== null && $audit->new !== null) : echo $this->getHtml('UPDATE', 'Auditor', 'Backend'); ?>
<?php elseif ($audit->new === null) : echo $this->getHtml('DELETE', 'Auditor', 'Backend'); ?>
<?php else : echo $this->getHtml('UNKNOWN', 'Auditor', 'Backend'); ?>
<?php endif; ?>
<td><a href="<?= $url; ?>"><?= $audit->trigger; ?></a>
<td><a class="content"
href="<?= UriFactory::build('{/base}/admin/account/settings?id=' . $audit->createdBy->id); ?>"><?= $this->printHtml(
$this->renderUserName('%3$s %2$s %1$s', [$audit->createdBy->name1, $audit->createdBy->name2, $audit->createdBy->name3, $audit->createdBy->login])
); ?></a>
<td><a href="<?= $url; ?>"><?= $audit->createdAt->format('Y-m-d H:i'); ?></a>
<?php endforeach; ?>
</table>
</div>
</div>
</div>
</div>
<input type="radio" id="c-tab-7" name="tabular-2">
<div class="tab">
<div class="row">
<div class="col-xs-12">
<div class="box wf-100">
<table class="default">
<caption><?= $this->getHtml('Logs'); ?><i class="fa fa-download end-xs download btn"></i></caption>
<thead>
<tr>
<td>IP
<td><?= $this->getHtml('ID', '0', '0'); ?>
<td><?= $this->getHtml('Name'); ?>
<td class="wf-100"><?= $this->getHtml('Log'); ?>
<td><?= $this->getHtml('Date'); ?>
<tbody>
<tr>
<td><?= $this->printHtml($this->request->getOrigin()); ?>
<td><?= $this->printHtml((string) $this->request->header->account); ?>
<td><?= $this->printHtml((string) $this->request->header->account); ?>
<td>Create Invoice
<td><?= $this->printHtml((new \DateTime('now'))->format('Y-m-d H:i:s')); ?>
</table>
</div>
</div>
</div>
</div>
<?php endif; ?>
</div>
</div>

View File

@ -21,7 +21,7 @@ echo $this->data['nav']->render(); ?>
<div class="row">
<div class="col-xs-12">
<div class="portlet">
<div class="portlet-head"><?= $this->getHtml('Bills'); ?><i class="lni lni-download download btn end-xs"></i></div>
<div class="portlet-head"><?= $this->getHtml('Bills'); ?><i class="g-icon download btn end-xs">download</i></div>
<div class="slider">
<table id="billList" class="default sticky">
<thead>
@ -33,134 +33,134 @@ echo $this->data['nav']->render(); ?>
<td><?= $this->getHtml('ID', '0', '0'); ?>
<label for="billList-sort-1">
<input type="radio" name="billList-sort" id="billList-sort-1">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-2">
<input type="radio" name="billList-sort" id="billList-sort-2">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td><?= $this->getHtml('Type'); ?>
<label for="billList-sort-3">
<input type="radio" name="billList-sort" id="billList-sort-3">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-4">
<input type="radio" name="billList-sort" id="billList-sort-4">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td><?= $this->getHtml('ClientID'); ?>
<label for="billList-sort-5">
<input type="radio" name="billList-sort" id="billList-sort-5">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-6">
<input type="radio" name="billList-sort" id="billList-sort-6">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td class="wf-100"><?= $this->getHtml('Client'); ?>
<label for="billList-sort-7">
<input type="radio" name="billList-sort" id="billList-sort-7">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-8">
<input type="radio" name="billList-sort" id="billList-sort-8">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td class="wf-100"><?= $this->getHtml('Address'); ?>
<label for="billList-sort-9">
<input type="radio" name="billList-sort" id="billList-sort-9">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-10">
<input type="radio" name="billList-sort" id="billList-sort-10">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td class="wf-100"><?= $this->getHtml('Postal'); ?>
<label for="billList-sort-11">
<input type="radio" name="billList-sort" id="billList-sort-11">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-12">
<input type="radio" name="billList-sort" id="billList-sort-12">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td class="wf-100"><?= $this->getHtml('City'); ?>
<label for="billList-sort-13">
<input type="radio" name="billList-sort" id="billList-sort-13">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-14">
<input type="radio" name="billList-sort" id="billList-sort-14">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td class="wf-100"><?= $this->getHtml('Country'); ?>
<label for="billList-sort-15">
<input type="radio" name="billList-sort" id="billList-sort-15">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-16">
<input type="radio" name="billList-sort" id="billList-sort-16">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td><?= $this->getHtml('Net'); ?>
<label for="billList-sort-7">
<input type="radio" name="billList-sort" id="billList-sort-7">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-18">
<input type="radio" name="billList-sort" id="billList-sort-18">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td><?= $this->getHtml('Profit'); ?>
<label for="billList-sort-21">
<input type="radio" name="billList-sort" id="billList-sort-21">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-22">
<input type="radio" name="billList-sort" id="billList-sort-22">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td><?= $this->getHtml('Created'); ?>
<label for="billList-sort-23">
<input type="radio" name="billList-sort" id="billList-sort-23">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-24">
<input type="radio" name="billList-sort" id="billList-sort-24">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<tbody>
<?php $count = 0; foreach ($bills as $key => $value) :
@ -174,7 +174,7 @@ echo $this->data['nav']->render(); ?>
</label>
<td><a href="<?= $url; ?>"><?= $value->getNumber(); ?></a>
<td><a href="<?= $url; ?>"><?= $value->type->getL11n(); ?></a>
<td><a class="content" href="<?= $client = UriFactory::build('sales/client/profile?{?}&id=' . $value->client->id); ?>"><?= $value->client->number; ?></a>
<td><a class="content" href="<?= $client = UriFactory::build('sales/client/view?{?}&id=' . $value->client->id); ?>"><?= $value->client->number; ?></a>
<td><a class="content" href="<?= $client; ?>"><?= $this->printHtml($value->billTo); ?></a>
<td><a href="<?= $url;
?>"><?= $value->billAddress; ?></a>

View File

@ -0,0 +1,71 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\ItemManagement
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
use phpOMS\Uri\UriFactory;
/** @var \phpOMS\Views\View $this */
$types = $this->data['types'];
echo $this->data['nav']->render(); ?>
<div class="row">
<div class="col-xs-12">
<section class="portlet">
<div class="portlet-head"><?= $this->getHtml('ShippingTerms'); ?><i class="g-icon download btn end-xs">download</i></div>
<div class="slider">
<table id="iContractTypeList" class="default sticky">
<thead>
<tr>
<td><?= $this->getHtml('ID', '0', '0'); ?>
<label for="iContractTypeList-sort-1">
<input type="radio" name="iContractTypeList-sort" id="iContractTypeList-sort-1">
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="iContractTypeList-sort-2">
<input type="radio" name="iContractTypeList-sort" id="iContractTypeList-sort-2">
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter g-icon">filter_alt</i>
</label>
<td class="wf-100"><?= $this->getHtml('Name'); ?>
<label for="iContractTypeList-sort-2">
<input type="radio" name="iContractTypeList-sort" id="iContractTypeList-sort-2">
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="iContractTypeList-sort-3">
<input type="radio" name="iContractTypeList-sort" id="iContractTypeList-sort-3">
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter g-icon">filter_alt</i>
</label>
<tbody>
<?php
$count = 0;
foreach ($types as $key => $value) : ++$count;
$url = UriFactory::build('{/base}/bill/shipping/view?{?}&id=' . $value->id);
?>
<tr data-href="<?= $url; ?>">
<td><a href="<?= $url; ?>"><?= $value->id; ?></a>
<td><a href="<?= $url; ?>"><?= $this->printHtml($value->getL11n()); ?></a>
<?php endforeach; ?>
<?php if ($count === 0) : ?>
<tr><td colspan="2" class="empty"><?= $this->getHtml('Empty', '0', '0'); ?>
<?php endif; ?>
</table>
</div>
</section>
</div>
</div>

View File

@ -0,0 +1,53 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\Billing
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
use phpOMS\Uri\UriFactory;
/** @var \phpOMS\Localization\BaseStringL11nType */
$type = $this->data['type'];
/** @var \phpOMS\Views\View $this */
echo $this->data['nav']->render(); ?>
<div class="row">
<div class="col-xs-12 col-md-6">
<div class="portlet">
<form id="shippingForm" method="POST" action="<?= UriFactory::build('{/api}bill/shipping'); ?>"
data-ui-container="#shippingTable tbody"
data-add-form="shippingForm"
data-add-tpl="#shippingTable tbody .oms-add-tpl-shipping">
<div class="portlet-head"><?= $this->getHtml('ShippingTerm'); ?></div>
<div class="portlet-body">
<div class="form-group">
<label for="iName"><?= $this->getHtml('Name'); ?></label>
<input type="text" name="code" id="iName" placeholder="" value="<?= $this->printHtml($type->title); ?>">
</div>
</div>
<div class="portlet-foot">
<input type="hidden" name="id" value="<?= $type->id; ?>">
<input id="iSubmit" name="submit" type="submit" value="<?= $this->getHtml('Save', '0', '0'); ?>">
</div>
</form>
</div>
</div>
</div>
<div class="row">
<?= $this->data['l11nView']->render(
$this->data['l11nValues'],
[],
'{/api}bill/shipping/l11n'
);
?>
</div>

View File

@ -23,7 +23,7 @@ echo $this->data['nav']->render(); ?>
<div class="row">
<div class="col-xs-12">
<div class="portlet">
<div class="portlet-head"><?= $this->getHtml('Bills'); ?><i class="lni lni-download download btn end-xs"></i></div>
<div class="portlet-head"><?= $this->getHtml('Bills'); ?><i class="g-icon download btn end-xs">download</i></div>
<div class="slider">
<table id="billList" class="default sticky">
<thead>
@ -35,122 +35,134 @@ echo $this->data['nav']->render(); ?>
<td><?= $this->getHtml('ID', '0', '0'); ?>
<label for="billList-sort-1">
<input type="radio" name="billList-sort" id="billList-sort-1">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-2">
<input type="radio" name="billList-sort" id="billList-sort-2">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td><?= $this->getHtml('External'); ?>
<label for="billList-sort-1">
<input type="radio" name="billList-sort" id="billList-sort-1">
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-2">
<input type="radio" name="billList-sort" id="billList-sort-2">
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter g-icon">filter_alt</i>
</label>
<td><?= $this->getHtml('Type'); ?>
<label for="billList-sort-3">
<input type="radio" name="billList-sort" id="billList-sort-3">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-4">
<input type="radio" name="billList-sort" id="billList-sort-4">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td><?= $this->getHtml('SupplierID'); ?>
<label for="billList-sort-5">
<input type="radio" name="billList-sort" id="billList-sort-5">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-6">
<input type="radio" name="billList-sort" id="billList-sort-6">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td class="wf-100"><?= $this->getHtml('Supplier'); ?>
<label for="billList-sort-7">
<input type="radio" name="billList-sort" id="billList-sort-7">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-8">
<input type="radio" name="billList-sort" id="billList-sort-8">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td class="wf-100"><?= $this->getHtml('Address'); ?>
<label for="billList-sort-9">
<input type="radio" name="billList-sort" id="billList-sort-9">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-10">
<input type="radio" name="billList-sort" id="billList-sort-10">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td class="wf-100"><?= $this->getHtml('Postal'); ?>
<label for="billList-sort-11">
<input type="radio" name="billList-sort" id="billList-sort-11">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-12">
<input type="radio" name="billList-sort" id="billList-sort-12">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td class="wf-100"><?= $this->getHtml('City'); ?>
<label for="billList-sort-13">
<input type="radio" name="billList-sort" id="billList-sort-13">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-14">
<input type="radio" name="billList-sort" id="billList-sort-14">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td class="wf-100"><?= $this->getHtml('Country'); ?>
<label for="billList-sort-15">
<input type="radio" name="billList-sort" id="billList-sort-15">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-16">
<input type="radio" name="billList-sort" id="billList-sort-16">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td><?= $this->getHtml('Gross'); ?>
<label for="billList-sort-7">
<input type="radio" name="billList-sort" id="billList-sort-7">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-18">
<input type="radio" name="billList-sort" id="billList-sort-18">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<td><?= $this->getHtml('Date'); ?>
<label for="billList-sort-23">
<input type="radio" name="billList-sort" id="billList-sort-23">
<i class="sort-asc fa fa-chevron-up"></i>
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="billList-sort-24">
<input type="radio" name="billList-sort" id="billList-sort-24">
<i class="sort-desc fa fa-chevron-down"></i>
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter fa fa-filter"></i>
<i class="filter g-icon">filter_alt</i>
</label>
<tbody>
<?php $count = 0;
@ -164,8 +176,9 @@ echo $this->data['nav']->render(); ?>
<span class="checkmark"></span>
</label>
<td><a href="<?= $url; ?>"><?= $value->getNumber(); ?></a>
<td><a href="<?= $url; ?>"><?= $value->external; ?></a>
<td><a href="<?= $url; ?>"><?= $value->type->getL11n(); ?></a>
<td><a class="content" href="<?= $supplier = UriFactory::build('purchase/supplier/profile?{?}&id=' . $value->supplier->id); ?>"><?= $value->supplier->number; ?></a>
<td><a class="content" href="<?= $supplier = UriFactory::build('purchase/supplier/view?{?}&id=' . $value->supplier->id); ?>"><?= $value->supplier->number; ?></a>
<td><a class="content" href="<?= $supplier; ?>"><?= $this->printHtml($value->billTo); ?></a>
<td><a href="<?= $url;
?>"><?= $value->billAddress; ?></a>
@ -176,7 +189,7 @@ echo $this->data['nav']->render(); ?>
: ISO3166NameEnum::getByName(
ISO3166TwoEnum::getName($value->billCountry)
); ?></a>
<td><a href="<?= $url; ?>"><?= $value->grossCosts->getAmount(); ?></a>
<td><a href="<?= $url; ?>"><?= $value->grossSales->getAmount(); ?></a>
<td><a href="<?= $url; ?>"><?= $value->billDate?->format('Y-m-d'); ?></a>
<?php endforeach; ?>
<?php if ($count === 0) : ?>

View File

@ -1,350 +0,0 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\Billing
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
use phpOMS\System\File\FileUtils;
use phpOMS\Uri\UriFactory;
// Media helper functions (e.g. file icon generator)
include __DIR__ . '/../../../Media/Theme/Backend/template-functions.php';
/**
* @var \phpOMS\Views\View $this
*/
$bill = $this->data['bill'];
$elements = $bill->getElements();
$previewType = $this->data['previewType'];
$originalType = $this->data['originalType'];
$billPdf = $bill->getFileByType($previewType);
$original = $bill->getFileByType($originalType);
$media = $bill->getMedia();
echo $this->data['nav']->render(); ?>
<div class="tabview tab-2">
<div class="box">
<ul class="tab-links">
<li><label for="c-tab-1"><?= $this->getHtml('Invoice'); ?></label></li>
<li><label for="c-tab-2"><?= $this->getHtml('Items'); ?></label></li>
<li><label for="c-tab-3"><?= $this->getHtml('Preview'); ?></label></li>
<li><label for="c-tab-4"><?= $this->getHtml('Original'); ?></label></li>
<li><label for="c-tab-5"><?= $this->getHtml('Payment'); ?></label></li>
<li><label for="c-tab-6"><?= $this->getHtml('Media'); ?></label></li>
<li><label for="c-tab-7"><?= $this->getHtml('Logs'); ?></label></li>
</ul>
</div>
<div class="tab-content">
<input type="radio" id="c-tab-1" name="tabular-2" checked>
<div class="tab">
<div class="row">
<div class="col-xs-12 col-md-6 col-lg-4">
<section class="portlet">
<form>
<div class="portlet-head"><?= $this->getHtml('Invoice'); ?></div>
<div class="portlet-body">
<table class="layout wf-100">
<tr><td><label for="iSource"><?= $this->getHtml('Source'); ?></label>
<tr><td><span class="input"><button type="button" formaction=""><i class="fa fa-book"></i></button><input type="text" id="iSource" name="source"></span>
<tr><td><label for="iType"><?= $this->getHtml('Type'); ?></label>
<tr><td><select id="iType" name="type">
<option><?= $this->getHtml('Invoice'); ?>
<option><?= $this->getHtml('Offer'); ?>
<option><?= $this->getHtml('Confirmation'); ?>
<option><?= $this->getHtml('DeliveryNote'); ?>
<option><?= $this->getHtml('CreditNote'); ?>
</select>
<tr><td><label for="iClient"><?= $this->getHtml('Client'); ?></label>
<tr><td><span class="input"><button type="button" formaction=""><i class="fa fa-book"></i></button><input type="text" id="iClient" name="client"></span>
<tr><td><label for="iDelivery"><?= $this->getHtml('Delivery'); ?></label>
<tr><td><input type="datetime-local" id="iDelivery" name="delivery">
<tr><td><label for="iDue"><?= $this->getHtml('Due'); ?></label>
<tr><td><input type="datetime-local" id="iDue" name="due">
<tr><td><label for="iFreightage"><?= $this->getHtml('Freightage'); ?></label>
<tr><td><input type="number" id="iFreightage" name="freightage">
<tr><td><label for="iShipment"><?= $this->getHtml('Shipment'); ?></label>
<tr><td><select id="iShipment" name="shipment">
<option>
</select>
<tr><td><label for="iTermsOfDelivery"><?= $this->getHtml('TermsOfDelivery'); ?></label>
<tr><td><select id="iTermsOfDelivery" name="termsofdelivery">
<option>
</select>
</table>
</div>
<div class="portlet-foot"><input type="submit" value="<?= $this->getHtml('Create', '0', '0'); ?>" name="create-bill"></div>
</form>
</section>
</div>
<div class="col-xs-12 col-md-6 col-lg-4">
<section class="portlet">
<div class="portlet-head"><?= $this->getHtml('Invoice'); ?></div>
<div class="portlet-body">
<form>
<table class="layout wf-100">
<tr><td><label for="iAddressS"><?= $this->getHtml('Addresses'); ?></label>
<tr><td><select id="iAddressS" name="addressS">
<option>
</select>
<tr><td><label for="iIRecipient"><?= $this->getHtml('Recipient'); ?></label>
<tr><td><input type="text" id="iIRecipient" name="irecipient">
<tr><td><label for="iAddress"><?= $this->getHtml('Address'); ?></label>
<tr><td><input type="text" id="iAddress" name="address">
<tr><td><label for="iZip"><?= $this->getHtml('Zip'); ?></label>
<tr><td><input type="text" id="iZip" name="zip">
<tr><td><label for="iCity"><?= $this->getHtml('City'); ?></label>
<tr><td><input type="text" id="iCity" name="city">
<tr><td><label for="iCountry"><?= $this->getHtml('Country'); ?></label>
<tr><td><input type="text" id="iCountry" name="country">
</table>
</form>
</div>
</section>
</div>
<div class="col-xs-12 col-md-6 col-lg-4">
<section class="portlet">
<div class="portlet-head"><?= $this->getHtml('Delivery'); ?></div>
<div class="portlet-body">
<form>
<table class="layout wf-100">
<tr><td><label for="iAddressS"><?= $this->getHtml('Addresses'); ?></label>
<tr><td><select id="iAddressS" name="addressS">
<option>
</select>
<tr><td><label for="iDRecipient"><?= $this->getHtml('Recipient'); ?></label>
<tr><td><input type="text" id="iDRecipient" name="drecipient">
<tr><td><label for="iAddress"><?= $this->getHtml('Address'); ?></label>
<tr><td><input type="text" id="iAddress" name="address">
<tr><td><label for="iZip"><?= $this->getHtml('Zip'); ?></label>
<tr><td><input type="text" id="iZip" name="zip">
<tr><td><label for="iCity"><?= $this->getHtml('City'); ?></label>
<tr><td><input type="text" id="iCity" name="city">
<tr><td><label for="iCountry"><?= $this->getHtml('Country'); ?></label>
<tr><td><input type="text" id="iCountry" name="country">
</table>
</form>
</div>
</section>
</div>
</div>
</div>
<input type="radio" id="c-tab-2" name="tabular-2">
<div class="tab">
<div class="row">
<div class="col-xs-12">
<div class="portlet">
<div class="portlet-head"><?= $this->getHtml('Invoice'); ?><i class="lni lni-download download btn end-xs"></i></div>
<table class="default" id="invoice-item-list">
<thead>
<tr>
<td>
<td><?= $this->getHtml('Item'); ?>
<td class="wf-100"><?= $this->getHtml('Name'); ?>
<td><?= $this->getHtml('Quantity'); ?>
<td><?= $this->getHtml('Price'); ?>
<td><?= $this->getHtml('Discount'); ?>
<td><?= $this->getHtml('DiscountP'); ?>
<td><?= $this->getHtml('Bonus'); ?>
<td><?= $this->getHtml('Tax'); ?>
<td><?= $this->getHtml('Net'); ?>
<tbody>
<?php foreach ($elements as $element) : ?>
<tr>
<td><i class="fa fa-plus add"></i> <i class="fa fa-chevron-up order-up"></i> <i class="fa fa-chevron-down order-down"></i>
<td><span class="input"><button type="button" formaction=""><i class="fa fa-book"></i></button><input name="" type="text" value="<?= $element->itemNumber; ?>" required></span>
<td><textarea required><?= $element->itemName; ?></textarea>
<td><input name="" type="number" min="0" value="<?= $element->quantity; ?>" required>
<td><input name="" type="text" value="<?= $this->getCurrency($element->singleSalesPriceNet); ?>">
<td><input name="" type="number" min="0">
<td><input name="" type="number" min="0" max="100" step="any">
<td><input name="" type="number" min="0" step="any">
<td><input name="" type="number" min="0" step="any">
<td><?= $this->getCurrency($element->totalSalesPriceNet); ?>
<?php endforeach; ?>
<tr>
<td><i class="fa fa-plus"></i> <i class="fa fa-chevron-up order-up"></i> <i class="fa fa-chevron-down order-down"></i>
<td><span class="input"><button type="button" formaction=""><i class="fa fa-book"></i></button><input name="" type="text" required></span>
<td><textarea required></textarea>
<td><input name="" type="number" min="0" value="0" required>
<td><input name="" type="text">
<td><input name="" type="number" min="0">
<td><input name="" type="number" min="0" max="100" step="any">
<td><input name="" type="number" min="0" step="any">
<td><input name="" type="number" min="0" step="any">
<td>
</table>
<div class="portlet-foot">
<?= $this->getHtml('Freightage'); ?>: 0.00 -
<?= $this->getHtml('Net'); ?>: <?= $this->getCurrency($bill->netSales); ?> -
<?= $this->getHtml('Tax'); ?>: 0.00 -
<?= $this->getHtml('Total'); ?>: <?= $this->getCurrency($bill->grossSales); ?>
</div>
</div>
</div>
</div>
</div>
<input type="radio" id="c-tab-3" name="tabular-2">
<div class="tab">
<div class="row">
<div class="col-xs-12">
<section id="mediaFile" class="portlet">
<div class="portlet-body">
<?php if ($billPdf->id > 0) : ?>
<iframe style="min-height: 600px;" data-form="iUiSettings" data-name="iframeHelper" id="iHelperFrame" src="<?= UriFactory::build('{/backend}Resources/mozilla/Pdf/web/viewer.html{?}&file=' . \urlencode(($billPdf->isAbsolute ? '' : '/../../../../') . $billPdf->getPath())); ?>" allowfullscreen></iframe>
<?php endif; ?>
</div>
</section>
</div>
</div>
</div>
<input type="radio" id="c-tab-4" name="tabular-2">
<div class="tab">
<div class="row">
<div class="col-xs-12">
<section id="mediaFile" class="portlet">
<div class="portlet-body">
<?php if ($original->id > 0) : ?>
<iframe style="min-height: 600px;" data-form="iUiSettings" data-name="iframeHelper" id="iHelperFrame" src="<?= UriFactory::build('{/backend}Resources/mozilla/Pdf/web/viewer.html{?}&file=' . \urlencode(($original->isAbsolute ? '' : '/../../../../') . $original->getPath())); ?>" allowfullscreen></iframe>
<?php endif; ?>
</div>
</section>
</div>
</div>
</div>
<input type="radio" id="c-tab-5" name="tabular-2">
<div class="tab">
<div class="row">
<div class="col-xs-12 col-md-6 col-lg-4">
<section class="box wf-100">
<header><h1><?= $this->getHtml('Payment'); ?></h1></header>
<div class="inner">
<form>
<table class="layout wf-100">
<tr><td><label for="iType"><?= $this->getHtml('Type'); ?></label>
<tr><td><select id="iType" name="type">
<option>
</select>
<tr><td><label for="iType"><?= $this->getHtml('Type'); ?></label>
<tr><td><select id="iType" name="type">
<option><?= $this->getHtml('MoneyTransfer'); ?>
<option><?= $this->getHtml('Prepaid'); ?>
<option><?= $this->getHtml('AlreadyPaid'); ?>
<option><?= $this->getHtml('CreditCard'); ?>
<option><?= $this->getHtml('DirectDebit'); ?>
</select>
<tr><td><label for="iDue"><?= $this->getHtml('Due'); ?></label>
<tr><td><input type="datetime-local" id="iDue" name="due">
<tr><td><label for="iDue"><?= $this->getHtml('Due'); ?> - <?= $this->getHtml('Cashback'); ?></label>
<tr><td><input type="datetime-local" id="iDue" name="due">
<tr><td><label for="iCashBack"><?= $this->getHtml('Cashback'); ?></label>
<tr><td><input type="number" id="iCashBack" name="cashback">
<tr><td><label for="iDue"><?= $this->getHtml('Due'); ?> - <?= $this->getHtml('Cashback'); ?> 2</label>
<tr><td><input type="datetime-local" id="iDue" name="due">
<tr><td><label for="iCashBack2"><?= $this->getHtml('Cashback'); ?> 2</label>
<tr><td><input type="number" id="iCashBack2" name="cashback2">
<tr><td><input type="submit" value="<?= $this->getHtml('Create', '0', '0'); ?>" name="create-bill">
</table>
</form>
</div>
</section>
</div>
</div>
</div>
<input type="radio" id="c-tab-6" name="tabular-2">
<div class="tab">
<div class="row">
<div class="col-xs-12 col-md-6 col-lg-4">
<section class="box wf-100">
<header><h1><?= $this->getHtml('Media'); ?></h1></header>
<div class="inner">
<form>
<table class="layout wf-100">
<tbody>
<tr><td colspan="2"><label for="iMedia"><?= $this->getHtml('Media'); ?></label>
<tr><td><input type="text" id="iMedia" placeholder="&#xf15b; File"><td><button><?= $this->getHtml('Select'); ?></button>
<tr><td colspan="2"><label for="iUpload"><?= $this->getHtml('Upload'); ?></label>
<tr><td><input type="file" id="iUpload" form="fTask"><input form="fTask" type="hidden" name="type"><td>
</table>
</form>
</div>
</section>
</div>
<div class="col-xs-12 col-md-6 col-lg-8">
<div class="portlet">
<div class="portlet-head"><?= $this->getHtml('Media'); ?><i class="lni lni-download download btn end-xs"></i></div>
<table class="default" id="invoice-item-list">
<thead>
<tr>
<td>
<td>
<td class="wf-100"><?= $this->getHtml('Name'); ?>
<td><?= $this->getHtml('Type'); ?>
<tbody>
<?php foreach ($media as $file) :
$url = $file->extension === 'collection'
? UriFactory::build('{/base}/media/list?path=' . \rtrim($file->getVirtualPath(), '/') . '/' . $file->name)
: UriFactory::build('{/base}/media/single?id=' . $file->id
. '&path={?path}' . (
$file->id === 0
? '/' . $file->name
: ''
)
);
$icon = $fileIconFunction(FileUtils::getExtensionType($file->extension));
?>
<tr data-href="<?= $url; ?>">
<td>
<td data-label="<?= $this->getHtml('Type'); ?>"><a href="<?= $url; ?>"><i class="fa fa-<?= $this->printHtml($icon); ?>"></i></a>
<td><a href="<?= $url; ?>"><?= $file->name; ?></a>
<td><a href="<?= $url; ?>"><?= $file->extension; ?></a>
<?php endforeach; ?>
</table>
</div>
</div>
</div>
</div>
<input type="radio" id="c-tab-7" name="tabular-2">
<div class="tab">
<div class="row">
<div class="col-xs-12">
<div class="box wf-100">
<table class="default">
<caption><?= $this->getHtml('Logs'); ?><i class="fa fa-download end-xs download btn"></i></caption>
<thead>
<tr>
<td>IP
<td><?= $this->getHtml('ID', '0', '0'); ?>
<td><?= $this->getHtml('Name'); ?>
<td class="wf-100"><?= $this->getHtml('Log'); ?>
<td><?= $this->getHtml('Date'); ?>
<tbody>
<tr>
<td><?= $this->printHtml($this->request->getOrigin()); ?>
<td><?= $this->printHtml((string) $this->request->header->account); ?>
<td><?= $this->printHtml((string) $this->request->header->account); ?>
<td>Create Invoice
<td><?= $this->printHtml((new \DateTime('now'))->format('Y-m-d H:i:s')); ?>
</table>
</div>
</div>
</div>
</div>
</div>
</div>

Some files were not shown because too many files have changed in this diff Show More