mirror of
https://github.com/Karaka-Management/oms-Billing.git
synced 2026-02-13 14:58:41 +00:00
fix billing process
This commit is contained in:
parent
2adbdc8765
commit
55b0d09005
14
.github/user_bug_report.md
vendored
14
.github/user_bug_report.md
vendored
|
|
@ -8,9 +8,11 @@ assignees: ''
|
||||||
---
|
---
|
||||||
|
|
||||||
# Bug Description
|
# Bug Description
|
||||||
|
|
||||||
A clear and concise description of what the bug is.
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
# How to Reproduce
|
# How to Reproduce
|
||||||
|
|
||||||
Steps to reproduce the behavior:
|
Steps to reproduce the behavior:
|
||||||
|
|
||||||
1. Go to '...'
|
1. Go to '...'
|
||||||
|
|
@ -19,16 +21,20 @@ Steps to reproduce the behavior:
|
||||||
4. See error
|
4. See error
|
||||||
|
|
||||||
# Expected Behavior
|
# Expected Behavior
|
||||||
|
|
||||||
A clear and concise description of what you expected to happen.
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
# Screenshots
|
# Screenshots
|
||||||
|
|
||||||
If applicable, add screenshots to help explain your problem.
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
# System Information
|
# System Information
|
||||||
- System: [e.g. PC or iPhone11, ...]
|
|
||||||
- OS: [e.g. iOS]
|
- System: [e.g. PC or iPhone11, ...]
|
||||||
- Browser [e.g. chrome, safari]
|
- OS: [e.g. iOS]
|
||||||
- KarakaVersion [e.g. 22]
|
- Browser [e.g. chrome, safari]
|
||||||
|
- KarakaVersion [e.g. 22]
|
||||||
|
|
||||||
# Additional Information
|
# Additional Information
|
||||||
|
|
||||||
Add any other context about the problem here.
|
Add any other context about the problem here.
|
||||||
|
|
|
||||||
9
Admin/Install/Admin.install.json
Normal file
9
Admin/Install/Admin.install.json
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"type": "setting",
|
||||||
|
"name": "1005100003",
|
||||||
|
"content": "[\"en\", \"de\"]",
|
||||||
|
"pattern": "",
|
||||||
|
"module": "Billing"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Karaka
|
|
||||||
*
|
|
||||||
* 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);
|
|
||||||
|
|
||||||
return [
|
|
||||||
];
|
|
||||||
43
Admin/Install/Admin.php
Normal file
43
Admin/Install/Admin.php
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Karaka
|
||||||
|
*
|
||||||
|
* PHP Version 8.1
|
||||||
|
*
|
||||||
|
* @package Modules\Billing\Admin\Install
|
||||||
|
* @copyright Dennis Eichhorn
|
||||||
|
* @license OMS License 2.0
|
||||||
|
* @version 1.0.0
|
||||||
|
* @link https://jingga.app
|
||||||
|
*/
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Modules\Billing\Admin\Install;
|
||||||
|
|
||||||
|
use phpOMS\Application\ApplicationAbstract;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Admin class.
|
||||||
|
*
|
||||||
|
* @package Modules\Billing\Admin\Install
|
||||||
|
* @license OMS License 2.0
|
||||||
|
* @link https://jingga.app
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
class Admin
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Install Admin providing
|
||||||
|
*
|
||||||
|
* @param ApplicationAbstract $app Application
|
||||||
|
* @param string $path Module path
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public static function install(ApplicationAbstract $app, string $path) : void
|
||||||
|
{
|
||||||
|
\Modules\Admin\Admin\Installer::installExternal($app, ['path' => __DIR__ . '/Admin.install.json']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,181 +12,208 @@
|
||||||
*/
|
*/
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
/** @var \phpOMS\Views\View $this */
|
use Modules\Billing\Models\NullBill;
|
||||||
|
use phpOMS\Localization\ISO3166NameEnum;
|
||||||
|
|
||||||
|
/** @var \phpOMS\Views\View $this */
|
||||||
require_once $this->getData('defaultTemplates')
|
require_once $this->getData('defaultTemplates')
|
||||||
->findFile('.pdf.php')
|
->findFile('.pdf.php')
|
||||||
->getAbsolutePath();
|
->getAbsolutePath();
|
||||||
|
|
||||||
|
/** @var \Modules\Billing\Models\Bill $bill */
|
||||||
|
$bill = $this->getData('bill') ?? new NullBill();
|
||||||
|
|
||||||
|
// Set up default pdf template
|
||||||
|
/** @phpstan-import-type DefaultPdf from ../../../../Admin/Install/Media/PdfDefaultTemplate/pdfTemplate.pdf.php */
|
||||||
$pdf = new DefaultPdf('P', 'mm', 'A4', true, 'UTF-8', false);
|
$pdf = new DefaultPdf('P', 'mm', 'A4', true, 'UTF-8', false);
|
||||||
|
|
||||||
$creator = $this->getData('bill_creator') ?? 'Jingga';
|
$lang = include __DIR__ . '/lang.php';
|
||||||
$author = 'Jingga';
|
|
||||||
$title = $this->getData('bill_title') ?? 'Invoice';
|
|
||||||
$subtitle = $this->getData('bill_subtitle') ?? 'Sub title';
|
|
||||||
$keywords = $this->getData('keywords') ?? [];
|
|
||||||
$logoName = $this->getData('bill_logo_name') ?? 'Jingga';
|
|
||||||
$slogan = $this->getData('bill_slogan') ?? 'Business solutions made simple.';
|
|
||||||
|
|
||||||
$legalCompanyName = $this->getData('legal_company_name') ?? 'Jingga e.K.';
|
$pdf->setHeaderData(
|
||||||
$companyAddress = $this->getData('bill_company_address') ?? 'Gartenstr. 26';
|
__DIR__ . '/logo.png', 15,
|
||||||
$companyCity = $this->getData('bill_company_city') ?? '61206 Woellstadt';
|
$this->getData('bill_logo_name') ?? 'Jingga',
|
||||||
$companyCEO = $this->getData('bill_company_ceo') ?? 'Dennis Eichhorn';
|
$this->getData('bill_slogan') ?? 'Business solutions made simple.'
|
||||||
$companyWebsite = $this->getData('bill_company_website') ?? 'www.jingga.app';
|
);
|
||||||
$companyEmail = $this->getData('bill_company_email') ?? 'info@jingga.app';
|
$pdf->setCreator($this->getData('bill_creator') ?? 'Jingga');
|
||||||
$companyPhone = $this->getData('bill_company_phone') ?? '+49 0152 ????';
|
$pdf->setAuthor($this->getData('bill_creator') ?? 'Jingga');
|
||||||
|
$pdf->setTitle($this->getData('bill_title') ?? $bill->type->getL11n());
|
||||||
|
$pdf->setSubject($this->getData('bill_subtitle') ?? '');
|
||||||
|
$pdf->setKeywords(\implode(', ', $this->getData('keywords') ?? []));
|
||||||
|
$pdf->language = $bill->getLanguage();
|
||||||
|
|
||||||
$taxOffice = $this->getData('bill_company_tax_office') ?? 'HRB';
|
$pdf->attributes['legal_name'] = $this->getData('legal_company_name') ?? 'Jingga e.K.';
|
||||||
$taxId = $this->getData('bill_company_tax_id') ?? 'DE ?????????';
|
$pdf->attributes['address'] = $this->getData('bill_company_address') ?? 'Gartenstr. 26';
|
||||||
$vatId = $this->getData('bill_company_vat_id') ?? 'DE ??????';
|
$pdf->attributes['city'] = $this->getData('bill_company_city') ?? '61206 Woellstadt';
|
||||||
|
|
||||||
$bankName = $this->getData('bill_company_bank_name') ?? 'Volksbank Mittelhessen';
|
$pdf->attributes['ceo'] = $this->getData('bill_company_ceo') ?? 'Dennis Eichhorn';
|
||||||
$bic = $this->getData('bill_company_bic') ?? '';
|
$pdf->attributes['tax_office'] = $this->getData('bill_company_tax_office') ?? 'HRB ???';
|
||||||
$iban = $this->getData('bill_company_iban') ?? '';
|
$pdf->attributes['tax_number'] = $this->getData('bill_company_tax_id') ?? '123456789';
|
||||||
|
|
||||||
$billTypeName = $this->getData('bill_type_name') ?? 'INVOICE';
|
$pdf->attributes['bank_name'] = $this->getData('bill_company_bank_name') ?? 'Volksbank Mittelhessen';
|
||||||
|
$pdf->attributes['swift'] = $this->getData('bill_company_swift') ?? '.....';
|
||||||
|
$pdf->attributes['bank_account'] = $this->getData('bill_company_bank_account') ?? '.....';
|
||||||
|
|
||||||
$billInvoiceNumber = $this->getData('bill_invoice_no') ?? '';
|
$pdf->attributes['website'] = $this->getData('bill_company_website') ?? 'www.jingga.app';
|
||||||
$billInvoiceDate = $this->getData('bill_invoice_date') ?? '';
|
$pdf->attributes['email'] = $this->getData('bill_company_email') ?? 'info@jingga.app';
|
||||||
$billServiceDate = $this->getData('bill_service_date') ?? '';
|
$pdf->attributes['phone'] = $this->getData('bill_company_phone') ?? '+49 0152 ????';
|
||||||
$billCustomerNo = $this->getData('bill_customer_no') ?? '';
|
|
||||||
$billPO = $this->getData('bill_po') ?? '';
|
|
||||||
$billDueDate = $this->getData('bill_due_date') ?? '';
|
|
||||||
|
|
||||||
$invoiceLines = $this->getData('bill_lines') ?? [];
|
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
|
||||||
|
|
||||||
$paymentTerms = $this->getData('bill_payment_terms') ?? '';
|
|
||||||
$terms = $this->getData('bill_terms') ?? 'https://jingga.app/terms';
|
|
||||||
$taxes = $this->getData('bill_taxes') ?? ['19%' => '0.00'];
|
|
||||||
$currency = $this->getData('bill_currency') ?? 'EUR';
|
|
||||||
|
|
||||||
// set document information
|
|
||||||
$pdf->SetCreator($creator);
|
|
||||||
$pdf->SetAuthor($author);
|
|
||||||
$pdf->SetTitle($title);
|
|
||||||
$pdf->SetSubject($subtitle);
|
|
||||||
$pdf->SetKeywords(\implode(', ', $keywords));
|
|
||||||
|
|
||||||
// set image scale factor
|
|
||||||
$pdf->SetImageScale(PDF_IMAGE_SCALE_RATIO);
|
|
||||||
|
|
||||||
|
// add a page
|
||||||
|
$pdf->AddPage();
|
||||||
$topPos = $pdf->getY();
|
$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
|
// Address
|
||||||
$pdf->SetY(55); // @todo: depending on amount of lines, there is a solution (html, or use backtracking of tcpdf)
|
$pdf->setY(55);
|
||||||
$pdf->SetFont('helvetica', '', 8);
|
$pdf->setFont('helvetica', '', 8);
|
||||||
|
|
||||||
|
$countries = ISO3166NameEnum::getConstants();
|
||||||
|
$toCountry = isset($countries[$bill->billCountry]) ? $countries[$bill->billCountry] : '';
|
||||||
|
|
||||||
|
$addressString = \trim(
|
||||||
|
$bill->billTo . "\n"
|
||||||
|
. (!empty($bill->billAddress) ? ($bill->billAddress . "\n") : '')
|
||||||
|
. (!empty($bill->billCity) ? ($bill->billCity . "\n") : '')
|
||||||
|
. (!empty($toCountry) ? ($toCountry . "\n") : ''),
|
||||||
|
"\n "
|
||||||
|
);
|
||||||
|
|
||||||
|
// Count the char "\n" in $addressString
|
||||||
|
$addressLineCount = \substr_count($addressString, "\n") + 1;
|
||||||
|
|
||||||
$lineHeight = $pdf->getY();
|
$lineHeight = $pdf->getY();
|
||||||
$pdf->Write(0, "Dennis Eichhorn\nGartenstr. 26\n61206 Woellstadt", '', 0, 'L', false, 0, false, false, 0);
|
$pdf->Write(
|
||||||
$lineHeight = ($lineHeight - $pdf->getY()) / 3;
|
0,
|
||||||
|
$addressString,
|
||||||
|
'', 0, 'L', false, 0, false, false, 0
|
||||||
|
);
|
||||||
|
$lineHeight = ($lineHeight - $pdf->getY()) / $addressLineCount;
|
||||||
|
|
||||||
// Document head
|
// Bill head
|
||||||
$pdf->SetFont('helvetica', 'B', 20);
|
$pdf->setFont('helvetica', 'B', 20);
|
||||||
$titleWidth = $pdf->GetStringWidth($billTypeName, 'helvetica', 'B', 20);
|
$titleWidth = $pdf->getStringWidth($billTypeName, 'helvetica', 'B', 20);
|
||||||
|
|
||||||
$pdf->SetXY(
|
$pdf->setXY(
|
||||||
$rightPos = ($pdf->getPageWidth() - $titleWidth - ($titleWidth < 55 ? 55 : 35) + 15),
|
$rightPos = ($pdf->getPageWidth() - $titleWidth - ($titleWidth < 55 ? 55 : 35) + 15),
|
||||||
$topPos + 50 + $lineHeight * 3 - 38,
|
$topPos + 50 + $lineHeight * $addressLineCount - 38,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
$pdf->SetTextColor(255, 255, 255);
|
$pdf->setTextColor(255, 255, 255);
|
||||||
$pdf->SetFillColor(255, 162, 7);
|
$pdf->setFillColor(255, 162, 7);
|
||||||
$pdf->Cell($pdf->getPageWidth() - $rightPos - 15, 0, $billTypeName, 0, 0, 'L', true);
|
$pdf->Cell($pdf->getPageWidth() - $rightPos - 15, 0, $billTypeName, 0, 0, 'L', true);
|
||||||
|
|
||||||
$pdf->SetFont('helvetica', '', 8);
|
$pdf->setFont('helvetica', '', 8);
|
||||||
$pdf->SetTextColor(255, 162, 7);
|
$pdf->setTextColor(255, 162, 7);
|
||||||
|
|
||||||
$pdf->SetXY($rightPos, $tempY = $pdf->getY() + 10, true);
|
$pdf->setXY($rightPos, $tempY = $pdf->getY() + 10, true);
|
||||||
$pdf->MultiCell(23, 30, "Invoice No\nInvoice Date\nService Date\nCustomer No\nPO\nDue Date", 0, 'L');
|
$pdf->MultiCell(
|
||||||
|
23, 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]['DueDate'],
|
||||||
|
0, 'L'
|
||||||
|
);
|
||||||
|
|
||||||
$pdf->SetFont('helvetica', '', 8);
|
$pdf->setFont('helvetica', '', 8);
|
||||||
$pdf->SetTextColor(0, 0, 0);
|
$pdf->setTextColor(0, 0, 0);
|
||||||
|
|
||||||
$pdf->SetXY($rightPos + 23 + 2, $tempY, true);
|
$pdf->setXY($rightPos + 23 + 2, $tempY, true);
|
||||||
$pdf->MultiCell(25, 30, "2022-123456\nYYYY-MM-DD\nYYYY-MM-DD\n123-456-789\n2022-123456\nYYYY-MM-DD", 0, 'L');
|
$pdf->MultiCell(
|
||||||
|
25, 30,
|
||||||
|
$bill->number . "\n"
|
||||||
|
. $bill->billDate->format('Y-m-d') . "\n"
|
||||||
|
. $bill->performanceDate->format('Y-m-d') . "\n"
|
||||||
|
. $bill->accountNumber . "\n"
|
||||||
|
. '' . "\n" /* @todo: implement customer / supplier reference as string */
|
||||||
|
. $bill->billDate->format('Y-m-d'), /* Consider to add dueDate in addition */
|
||||||
|
0, 'L'
|
||||||
|
);
|
||||||
$pdf->Ln();
|
$pdf->Ln();
|
||||||
|
|
||||||
$pdf->SetY($pdf->GetY() - 30);
|
$pdf->setY($pdf->getY() - 30);
|
||||||
|
|
||||||
|
/*
|
||||||
$pdf->writeHTMLCell(
|
$pdf->writeHTMLCell(
|
||||||
$pdf->getPageWidth() - 15 * 2, 0, null, null,
|
$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.",
|
"<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'
|
0, 0, false, true, 'J'
|
||||||
);
|
);
|
||||||
$pdf->Ln();
|
$pdf->Ln();
|
||||||
|
*/
|
||||||
|
|
||||||
$pdf->SetY($pdf->GetY() + 5);
|
$pdf->setY($pdf->getY() + 5);
|
||||||
|
|
||||||
$header = ['Item', 'Quantity', 'Rate', 'Total'];
|
$header = [
|
||||||
$data = [
|
$lang[$pdf->language]['Item'],
|
||||||
['ASDF', 2.0, 199.90, 399.80],
|
$lang[$pdf->language]['Quantity'],
|
||||||
["123-456-789<br><strong>This is a item name</strong><br><span style=\"color: #444;\">This is the item description in more detail for the customer so he knows what this content actually contains.</span>", 2.0, 199.90, 399.80],
|
$lang[$pdf->language]['UnitPrice'],
|
||||||
["123-456-789<br><strong>This is a item name</strong><br><span style=\"color: #444;\">This is the item description in more detail for the customer.</span>", 2.0, "199.90\n-10 %", "150.399.80\n-15.039"],
|
$lang[$pdf->language]['Total']
|
||||||
["123-456-789<br><strong>This is a item name</strong><br><span style=\"color: #444;\">This is the item description in more detail for the customer so he knows what this content actually contains.</span>", 2.0, 199.90, 399.80],
|
|
||||||
["123-456-789<br><strong>This is a item name</strong><br><span style=\"color: #444;\">This is the item description in more detail for the customer so he knows what this content actually contains. Here we are testing how it looks like if a very long text is posted in the description without any additional line breaks. It should auto-break!</span>", 2.0, 199.90, 399.80],
|
|
||||||
["123-456-789<br><strong>This is a item name</strong><br><span style=\"color: #444;\">This is the item description in more detail for the customer so he knows what this content actually contains.</span>", 2.0, 199.90, 399.80],
|
|
||||||
["123-456-789<br><strong>This is a item name</strong><br><span style=\"color: #444;\">This is the item description in more detail for the customer so he knows what this content actually contains.</span>", 2.0, 199.90, 399.80],
|
|
||||||
["123-456-789<br><strong>This is a item name</strong><br><span style=\"color: #444;\">This is the item description in more detail for the customer so he knows what this content actually contains.</span>", 2.0, 199.90, 399.80],
|
|
||||||
["123-456-789<br><strong>This is a item name</strong><br><span style=\"color: #444;\">This is the item description in more detail for the customer so he knows what this content actually contains.</span>", 2.0, 199.90, 399.80],
|
|
||||||
["123-456-789<br><strong>This is a item name</strong><br><span style=\"color: #444;\">This is the item description in more detail for the customer so he knows what this content actually contains.</span>", 2.0, 199.90, 399.80],
|
|
||||||
["123-456-789<br><strong>This is a item name</strong><br><span style=\"color: #444;\">This is the item description in more detail for the customer so he knows what this content actually contains.</span>", 2.0, 199.90, 399.80],
|
|
||||||
["123-456-789<br><strong>This is a item name</strong><br><span style=\"color: #444;\">This is the item description in more detail for the customer so he knows what this content actually contains.</span>", 2.0, 199.90, 399.80],
|
|
||||||
["123-456-789<br><strong>This is a item name</strong><br><span style=\"color: #444;\">This is the item description in more detail for the customer so he knows what this content actually contains.</span>", 2.0, 199.90, 399.80],
|
|
||||||
["123-456-789<br><strong>This is a item name</strong><br><span style=\"color: #444;\">This is the item description in more detail for the customer so he knows what this content actually contains.</span>", 2.0, 199.90, 399.80],
|
|
||||||
["123-456-789<br><strong>This is a item name</strong><br><span style=\"color: #444;\">This is the item description in more detail for the customer so he knows what this content actually contains.</span>", 2.0, 199.90, 399.80],
|
|
||||||
['ASDF', 2.0, 199.90, 399.80],
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
$lines = $bill->getElements();
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
$w = array($pdf->getPageWidth() - 20 - 20 - 20 - 2*15, 20, 20, 20);
|
$headerCount = \count($header);
|
||||||
$num_headers = \count($header);
|
$w = [$pdf->getPageWidth() - 20 - 20 - 20 - 2*15, 20, 20, 20];
|
||||||
|
|
||||||
$pdf->setCellPadding(1, 1, 1, 1);
|
$pdf->setCellPadding(1, 1, 1, 1);
|
||||||
|
|
||||||
|
$taxes = [];
|
||||||
$first = true;
|
$first = true;
|
||||||
|
|
||||||
// Data
|
// Data
|
||||||
$fill = false;
|
$fill = false;
|
||||||
foreach($data as $row) {
|
foreach($lines as $line) {
|
||||||
if ($row === null || $first || $pdf->getY() > $pdf->getPageHeight() - 40) {
|
// @todo: add support for empty lines (row = line)
|
||||||
$pdf->SetFillColor(255, 162, 7);
|
if (/*$row === null || */$first || $pdf->getY() > $pdf->getPageHeight() - 40) {
|
||||||
$pdf->SetTextColor(255);
|
$pdf->setFillColor(255, 162, 7);
|
||||||
$pdf->SetDrawColor(255, 162, 7);
|
$pdf->setTextColor(255);
|
||||||
|
$pdf->setDrawColor(255, 162, 7);
|
||||||
//$pdf->SetLineWidth(0.3);
|
//$pdf->SetLineWidth(0.3);
|
||||||
$pdf->SetFont('helvetica', 'B', 8);
|
$pdf->setFont('helvetica', 'B', 8);
|
||||||
|
|
||||||
if (!$first || $row === null) {
|
if (!$first/* || $row === null*/) {
|
||||||
$pdf->AddPage();
|
$pdf->AddPage();
|
||||||
$pdf->Ln();
|
$pdf->Ln();
|
||||||
}
|
}
|
||||||
|
|
||||||
for($i = 0; $i < $num_headers; ++$i) {
|
for($i = 0; $i < $headerCount; ++$i) {
|
||||||
$pdf->Cell($w[$i], 7, $header[$i], 1, 0, 'L', true);
|
$pdf->Cell($w[$i], 7, $header[$i], 1, 0, 'L', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$pdf->Ln();
|
$pdf->Ln();
|
||||||
$pdf->SetFillColor(245, 245, 245);
|
$pdf->setFillColor(245, 245, 245);
|
||||||
$pdf->SetTextColor(0);
|
$pdf->setTextColor(0);
|
||||||
$pdf->SetFont('helvetica', '', 8);
|
$pdf->setFont('helvetica', '', 8);
|
||||||
|
|
||||||
$first = false;
|
$first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$tempY = $pdf->getY();
|
$tempY = $pdf->getY();
|
||||||
$pdf->writeHTMLCell($w[0], 10, null, null, $row[0], 0, 2, $fill);
|
$pdf->writeHTMLCell($w[0], 10, null, null, $line->itemNumber . ' ' . $line->itemName, 0, 2, $fill);
|
||||||
$height = $pdf->getY() - $tempY;
|
$height = $pdf->getY() - $tempY;
|
||||||
|
|
||||||
/*
|
$pdf->MultiCell($w[1], $height, $line->getQuantity(), 0, 'L', $fill, 0, 15 + $w[0], $tempY, true, 0, false, true, 0, 'M', true);
|
||||||
$pdf->writeHTMLCell($w[1], $height, 15 + $w[0], $tempY, $row[1], 0, 0, $fill);
|
$pdf->MultiCell($w[2], $height, $line->singleSalesPriceNet->getCurrency(2, symbol: ''), 0, 'L', $fill, 0, 15 + $w[0] + $w[1], $tempY, true, 0, false, true, 0, 'M', true);
|
||||||
$pdf->writeHTMLCell($w[2], $height, 15 + $w[0] + $w[1], $tempY, $row[2], 0, 0, $fill);
|
$pdf->MultiCell($w[3], $height, $line->totalSalesPriceNet->getCurrency(2, symbol: ''), 0, 'L', $fill, 1, 15 + $w[0] + $w[1] + $w[2], $tempY, true, 0, false, true, 0, 'M', true);
|
||||||
$pdf->writeHTMLCell($w[3], $height, 15 + $w[0] + $w[1] + $w[2], $tempY, $row[3], 0, 1, $fill);
|
|
||||||
*/
|
|
||||||
|
|
||||||
$pdf->MultiCell($w[1], $height, $row[1], 0, 'L', $fill, 0, 15 + $w[0], $tempY, true, 0, false, true, 0, 'M', true);
|
|
||||||
$pdf->MultiCell($w[2], $height, $row[2], 0, 'L', $fill, 0, 15 + $w[0] + $w[1], $tempY, true, 0, false, true, 0, 'M', true);
|
|
||||||
$pdf->MultiCell($w[3], $height, $row[3], 0, 'L', $fill, 1, 15 + $w[0] + $w[1] + $w[2], $tempY, true, 0, false, true, 0, 'M', true);
|
|
||||||
|
|
||||||
$fill = !$fill;
|
$fill = !$fill;
|
||||||
|
|
||||||
|
// get taxes
|
||||||
|
if (!isset($taxes[$line->taxR->getInt() / 100])) {
|
||||||
|
$taxes[$line->taxR->getInt() / 100] = $line->taxP;
|
||||||
|
} else {
|
||||||
|
$taxes[$line->taxR->getInt() / 100]->add($line->taxP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$pdf->Cell(\array_sum($w), 0, '', 'T');
|
$pdf->Cell(\array_sum($w), 0, '', 'T');
|
||||||
|
|
@ -196,68 +223,71 @@ if ($pdf->getY() > $pdf->getPageHeight() - 40) {
|
||||||
$pdf->AddPage();
|
$pdf->AddPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
$pdf->SetFillColor(240, 240, 240);
|
$pdf->setFillColor(240, 240, 240);
|
||||||
$pdf->SetTextColor(0);
|
$pdf->setTextColor(0);
|
||||||
$pdf->SetDrawColor(240, 240, 240);
|
$pdf->setDrawColor(240, 240, 240);
|
||||||
$pdf->SetFont('helvetica', 'B', 8);
|
$pdf->setFont('helvetica', 'B', 8);
|
||||||
|
|
||||||
$tempY = $pdf->GetY();
|
$tempY = $pdf->getY();
|
||||||
|
|
||||||
$pdf->SetX($w[0] + $w[1] + 15);
|
$pdf->setX($w[0] + $w[1] + 15);
|
||||||
$pdf->Cell($w[2], 7, 'Subtotal', 0, 0, 'L', false);
|
$pdf->Cell($w[2], 7, $lang[$pdf->language]['Subtotal'], 0, 0, 'L', false);
|
||||||
$pdf->Cell($w[3], 7, '40.000', 0, 0, 'L', false);
|
$pdf->Cell($w[3], 7, $bill->netSales->getCurrency(2, symbol: ''), 0, 0, 'L', false);
|
||||||
$pdf->Ln();
|
|
||||||
$pdf->SetX($w[0] + $w[1] + 15);
|
|
||||||
$pdf->Cell($w[2], 7, 'Taxes (0%)', 0, 0, 'L', false);
|
|
||||||
$pdf->Cell($w[3], 7, '40.000', 0, 0, 'L', false);
|
|
||||||
$pdf->Ln();
|
|
||||||
$pdf->SetX($w[0] + $w[1] + 15);
|
|
||||||
$pdf->Cell($w[2], 7, 'Taxes (16%)', 0, 0, 'L', false);
|
|
||||||
$pdf->Cell($w[3], 7, '40.000', 0, 0, 'L', false);
|
|
||||||
$pdf->Ln();
|
|
||||||
$pdf->SetX($w[0] + $w[1] + 15);
|
|
||||||
$pdf->Cell($w[2], 7, 'Taxes (19%)', 0, 0, 'L', false);
|
|
||||||
$pdf->Cell($w[3], 7, '40.000', 0, 0, 'L', false);
|
|
||||||
$pdf->Ln();
|
$pdf->Ln();
|
||||||
|
|
||||||
$pdf->SetFillColor(255, 162, 7);
|
foreach ($taxes as $rate => $tax) {
|
||||||
$pdf->SetTextColor(255);
|
$pdf->setX($w[0] + $w[1] + 15);
|
||||||
$pdf->SetDrawColor(255, 162, 7);
|
$pdf->Cell($w[2], 7, $lang[$pdf->language]['Taxes'] . ' (' . $rate . '%)', 0, 0, 'L', false);
|
||||||
$pdf->SetFont('helvetica', 'B', 8);
|
$pdf->Cell($w[3], 7, $tax->getCurrency(2, symbol: ''), 0, 0, 'L', false);
|
||||||
|
$pdf->Ln();
|
||||||
|
}
|
||||||
|
|
||||||
$pdf->SetX($w[0] + $w[1] + 15);
|
// @todo: add currency
|
||||||
$pdf->Cell($w[2], 7, 'TOTAL', 1, 0, 'L', true);
|
|
||||||
$pdf->Cell($w[3], 7, '40.000', 1, 0, 'L', true);
|
$pdf->setFillColor(255, 162, 7);
|
||||||
|
$pdf->setTextColor(255);
|
||||||
|
$pdf->setDrawColor(255, 162, 7);
|
||||||
|
$pdf->setFont('helvetica', 'B', 8);
|
||||||
|
|
||||||
|
$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, $bill->grossSales->getCurrency(2, symbol: ''), 1, 0, 'L', true);
|
||||||
$pdf->Ln();
|
$pdf->Ln();
|
||||||
|
|
||||||
$tempY2 = $pdf->getY();
|
$tempY2 = $pdf->getY();
|
||||||
|
|
||||||
$pdf->SetTextColor(0);
|
// @todo: fix payment terms
|
||||||
$pdf->SetFont('helvetica', 'B', 8);
|
$pdf->setTextColor(0);
|
||||||
$pdf->SetY($tempY);
|
$pdf->setFont('helvetica', 'B', 8);
|
||||||
$pdf->Write(0, 'Payment Terms: ', '', 0, 'L', false, 0, false, false, 0);
|
$pdf->setY($tempY);
|
||||||
|
$pdf->Write(0, $lang[$pdf->language]['PaymentTerms'] . ': CreditCard', '', 0, 'L', false, 0, false, false, 0);
|
||||||
|
|
||||||
$pdf->SetFont('helvetica', '', 8);
|
$pdf->setFont('helvetica', '', 8);
|
||||||
$pdf->Write(0, 'Payment within 30 business days', '', 0, 'L', false, 0, false, false, 0);
|
$pdf->Write(0, $bill->paymentText, '', 0, 'L', false, 0, false, false, 0);
|
||||||
$pdf->Ln();
|
$pdf->Ln();
|
||||||
|
|
||||||
$pdf->SetFont('helvetica', 'B', 8);
|
// @todo: fix terms
|
||||||
$pdf->Write(0, 'Terms: ', '', 0, 'L', false, 0, false, false, 0);
|
$pdf->setFont('helvetica', 'B', 8);
|
||||||
|
$pdf->Write(0, $lang[$pdf->language]['Terms'] . ': https://jingga.app/terms', '', 0, 'L', false, 0, false, false, 0);
|
||||||
|
|
||||||
$pdf->SetFont('helvetica', '', 8);
|
$pdf->setFont('helvetica', '', 8);
|
||||||
$pdf->Write(0, 'https://jingga.app/terms', '', 0, 'L', false, 0, false, false, 0);
|
$pdf->Write(0, $bill->termsText, '', 0, 'L', false, 0, false, false, 0);
|
||||||
$pdf->Ln();
|
$pdf->Ln();
|
||||||
|
|
||||||
$pdf->SetY($tempY2);
|
$pdf->setY($tempY2);
|
||||||
$pdf->Ln();
|
$pdf->Ln();
|
||||||
|
|
||||||
// $pdf->SetY($pdf->GetY() - 30);
|
/*
|
||||||
$pdf->writeHTMLCell(
|
$pdf->writeHTMLCell(
|
||||||
$pdf->getPageWidth() - 15 * 2, 0, null, null,
|
$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.",
|
"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'
|
0, 0, false, true, 'J'
|
||||||
);
|
);
|
||||||
$pdf->Ln();
|
$pdf->Ln();
|
||||||
|
*/
|
||||||
|
|
||||||
//Close and output PDF document
|
//Close and output PDF document
|
||||||
$pdf->Output('example_048.pdf', 'I');
|
$pdf->Output(
|
||||||
|
$this->getData('path') ?? ($bill->billDate->format('Y-m-d') . '_' . $bill->number . '.pdf'),
|
||||||
|
'I'
|
||||||
|
);
|
||||||
|
|
|
||||||
42
Admin/Install/Media/lang.php
Normal file
42
Admin/Install/Media/lang.php
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'en' => [
|
||||||
|
'InvoiceNo' => 'Invoice No.',
|
||||||
|
'InvoiceDate' => 'Invoice Date',
|
||||||
|
'ServiceDate' => 'Service Date',
|
||||||
|
'CustomerNo' => 'Customer No.',
|
||||||
|
'PO' => 'PO',
|
||||||
|
'DueDate' => 'Due Date',
|
||||||
|
'Item' => 'Item',
|
||||||
|
'Quantity' => 'Quantity',
|
||||||
|
'UnitPrice' => 'Unit Price',
|
||||||
|
'Total' => 'Total',
|
||||||
|
'Net' => 'Net',
|
||||||
|
'Gross' => 'Gross',
|
||||||
|
'Subtotal' => 'Subtotal',
|
||||||
|
'Taxes' => 'Taxes',
|
||||||
|
'Terms' => 'Terms',
|
||||||
|
'PaymentTerms' => 'Payment Terms',
|
||||||
|
],
|
||||||
|
'de' => [
|
||||||
|
'InvoiceNo' => 'Belegnummer',
|
||||||
|
'InvoiceDate' => 'Belegdatum',
|
||||||
|
'ServiceDate' => 'Leistungsdatum',
|
||||||
|
'CustomerNo' => 'Kundennummer',
|
||||||
|
'PO' => 'Kundenreferenz',
|
||||||
|
'DueDate' => 'Fälligkeitsdatum',
|
||||||
|
'Item' => 'Artikel',
|
||||||
|
'Quantity' => 'Menge',
|
||||||
|
'UnitPrice' => 'Einzelpreis',
|
||||||
|
'Total' => 'Gesamt',
|
||||||
|
'Net' => 'Netto',
|
||||||
|
'Gross' => 'Brutto',
|
||||||
|
'Subtotal' => 'Netto',
|
||||||
|
'Taxes' => 'USt',
|
||||||
|
'Terms' => 'AGB',
|
||||||
|
'PaymentTerms' => 'Zahlungsbedingungen',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
@ -393,11 +393,6 @@
|
||||||
"type": "VARCHAR(255)",
|
"type": "VARCHAR(255)",
|
||||||
"null": false
|
"null": false
|
||||||
},
|
},
|
||||||
"billing_bill_numberformat": {
|
|
||||||
"name": "billing_bill_numberformat",
|
|
||||||
"type": "VARCHAR(255)",
|
|
||||||
"null": false
|
|
||||||
},
|
|
||||||
"billing_bill_info": {
|
"billing_bill_info": {
|
||||||
"name": "billing_bill_info",
|
"name": "billing_bill_info",
|
||||||
"type": "TEXT",
|
"type": "TEXT",
|
||||||
|
|
@ -405,7 +400,12 @@
|
||||||
},
|
},
|
||||||
"billing_bill_status": {
|
"billing_bill_status": {
|
||||||
"name": "billing_bill_status",
|
"name": "billing_bill_status",
|
||||||
"type": "INT",
|
"type": "TINYINT",
|
||||||
|
"null": false
|
||||||
|
},
|
||||||
|
"billing_bill_paymentstatus": {
|
||||||
|
"name": "billing_bill_paymentstatus",
|
||||||
|
"type": "TINYINT",
|
||||||
"null": false
|
"null": false
|
||||||
},
|
},
|
||||||
"billing_bill_type": {
|
"billing_bill_type": {
|
||||||
|
|
@ -423,6 +423,11 @@
|
||||||
"foreignTable": "media",
|
"foreignTable": "media",
|
||||||
"foreignKey": "media_id"
|
"foreignKey": "media_id"
|
||||||
},
|
},
|
||||||
|
"billing_bill_account_no": {
|
||||||
|
"name": "billing_bill_account_no",
|
||||||
|
"type": "VARCHAR(50)",
|
||||||
|
"null": false
|
||||||
|
},
|
||||||
"billing_bill_supplier": {
|
"billing_bill_supplier": {
|
||||||
"name": "billing_bill_supplier",
|
"name": "billing_bill_supplier",
|
||||||
"type": "INT",
|
"type": "INT",
|
||||||
|
|
|
||||||
|
|
@ -111,9 +111,9 @@ final class ApiAttributeController extends Controller
|
||||||
private function validateBillAttributeCreate(RequestAbstract $request) : array
|
private function validateBillAttributeCreate(RequestAbstract $request) : array
|
||||||
{
|
{
|
||||||
$val = [];
|
$val = [];
|
||||||
if (($val['type'] = empty($request->getData('type')))
|
if (($val['type'] = !$request->hasData('type'))
|
||||||
|| ($val['value'] = (empty($request->getData('value')) && empty($request->getData('custom'))))
|
|| ($val['value'] = (!$request->hasData('value') && !$request->hasData('custom')))
|
||||||
|| ($val['bill'] = empty($request->getData('bill')))
|
|| ($val['bill'] = !$request->hasData('bill'))
|
||||||
) {
|
) {
|
||||||
return $val;
|
return $val;
|
||||||
}
|
}
|
||||||
|
|
@ -181,8 +181,8 @@ final class ApiAttributeController extends Controller
|
||||||
private function validateBillAttributeTypeL11nCreate(RequestAbstract $request) : array
|
private function validateBillAttributeTypeL11nCreate(RequestAbstract $request) : array
|
||||||
{
|
{
|
||||||
$val = [];
|
$val = [];
|
||||||
if (($val['title'] = empty($request->getData('title')))
|
if (($val['title'] = !$request->hasData('title'))
|
||||||
|| ($val['type'] = empty($request->getData('type')))
|
|| ($val['type'] = !$request->hasData('type'))
|
||||||
) {
|
) {
|
||||||
return $val;
|
return $val;
|
||||||
}
|
}
|
||||||
|
|
@ -252,8 +252,8 @@ final class ApiAttributeController extends Controller
|
||||||
private function validateBillAttributeTypeCreate(RequestAbstract $request) : array
|
private function validateBillAttributeTypeCreate(RequestAbstract $request) : array
|
||||||
{
|
{
|
||||||
$val = [];
|
$val = [];
|
||||||
if (($val['title'] = empty($request->getData('title')))
|
if (($val['title'] = !$request->hasData('title'))
|
||||||
|| ($val['name'] = empty($request->getData('name')))
|
|| ($val['name'] = !$request->hasData('name'))
|
||||||
) {
|
) {
|
||||||
return $val;
|
return $val;
|
||||||
}
|
}
|
||||||
|
|
@ -337,8 +337,8 @@ final class ApiAttributeController extends Controller
|
||||||
private function validateBillAttributeValueCreate(RequestAbstract $request) : array
|
private function validateBillAttributeValueCreate(RequestAbstract $request) : array
|
||||||
{
|
{
|
||||||
$val = [];
|
$val = [];
|
||||||
if (($val['type'] = empty($request->getData('type')))
|
if (($val['type'] = !$request->hasData('type'))
|
||||||
|| ($val['value'] = empty($request->getData('value')))
|
|| ($val['value'] = !$request->hasData('value'))
|
||||||
) {
|
) {
|
||||||
return $val;
|
return $val;
|
||||||
}
|
}
|
||||||
|
|
@ -406,8 +406,8 @@ final class ApiAttributeController extends Controller
|
||||||
private function validateBillAttributeValueL11nCreate(RequestAbstract $request) : array
|
private function validateBillAttributeValueL11nCreate(RequestAbstract $request) : array
|
||||||
{
|
{
|
||||||
$val = [];
|
$val = [];
|
||||||
if (($val['title'] = empty($request->getData('title')))
|
if (($val['title'] = !$request->hasData('title'))
|
||||||
|| ($val['value'] = empty($request->getData('value')))
|
|| ($val['value'] = !$request->hasData('value'))
|
||||||
) {
|
) {
|
||||||
return $val;
|
return $val;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,14 @@ use Modules\Billing\Models\BillElementMapper;
|
||||||
use Modules\Billing\Models\BillMapper;
|
use Modules\Billing\Models\BillMapper;
|
||||||
use Modules\Billing\Models\BillStatus;
|
use Modules\Billing\Models\BillStatus;
|
||||||
use Modules\Billing\Models\BillTypeMapper;
|
use Modules\Billing\Models\BillTypeMapper;
|
||||||
|
use Modules\Billing\Models\SettingsEnum;
|
||||||
|
use Modules\Billing\Models\Tax\TaxCombinationMapper;
|
||||||
use Modules\ClientManagement\Models\Client;
|
use Modules\ClientManagement\Models\Client;
|
||||||
use Modules\ClientManagement\Models\ClientMapper;
|
use Modules\ClientManagement\Models\ClientMapper;
|
||||||
|
use Modules\Finance\Models\TaxCode;
|
||||||
|
use Modules\Finance\Models\TaxCodeMapper;
|
||||||
|
use Modules\ItemManagement\Models\Item;
|
||||||
|
use Modules\ItemManagement\Models\ItemL11nMapper;
|
||||||
use Modules\ItemManagement\Models\ItemMapper;
|
use Modules\ItemManagement\Models\ItemMapper;
|
||||||
use Modules\Media\Models\CollectionMapper;
|
use Modules\Media\Models\CollectionMapper;
|
||||||
use Modules\Media\Models\MediaMapper;
|
use Modules\Media\Models\MediaMapper;
|
||||||
|
|
@ -99,7 +105,7 @@ final class ApiBillController extends Controller
|
||||||
private function validateBillUpdate(RequestAbstract $request) : array
|
private function validateBillUpdate(RequestAbstract $request) : array
|
||||||
{
|
{
|
||||||
$val = [];
|
$val = [];
|
||||||
if (($val['bill'] = empty($request->getData('bill')))) {
|
if (($val['bill'] = !$request->hasData('bill'))) {
|
||||||
return $val;
|
return $val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -147,7 +153,6 @@ final class ApiBillController extends Controller
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @todo: validate vat before creation
|
|
||||||
$bill = $this->createBillFromRequest($request, $response, $data);
|
$bill = $this->createBillFromRequest($request, $response, $data);
|
||||||
$this->createBillDatabaseEntry($bill, $request);
|
$this->createBillDatabaseEntry($bill, $request);
|
||||||
|
|
||||||
|
|
@ -168,9 +173,9 @@ final class ApiBillController extends Controller
|
||||||
{
|
{
|
||||||
$this->createModel($request->header->account, $bill, BillMapper::class, 'bill', $request->getOrigin());
|
$this->createModel($request->header->account, $bill, BillMapper::class, 'bill', $request->getOrigin());
|
||||||
|
|
||||||
$new = clone $bill;
|
$old = clone $bill;
|
||||||
$new->buildNumber(); // The bill id is part of the number
|
$bill->buildNumber(); // The bill id is part of the number
|
||||||
$this->updateModel($request->header->account, $bill, $new, BillMapper::class, 'bill', $request->getOrigin());
|
$this->updateModel($request->header->account, $old, $bill, BillMapper::class, 'bill', $request->getOrigin());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -181,7 +186,7 @@ final class ApiBillController extends Controller
|
||||||
*
|
*
|
||||||
* @return Bill The new Bill object with default values
|
* @return Bill The new Bill object with default values
|
||||||
*
|
*
|
||||||
* @todo Validate VAT before creation
|
* @todo Validate VAT before creation (maybe need to add a status when last validated, we don't want to validate every time)
|
||||||
* @todo Set the correct date of payment
|
* @todo Set the correct date of payment
|
||||||
* @todo Use bill and shipping address instead of main address if available
|
* @todo Use bill and shipping address instead of main address if available
|
||||||
* @todo Implement allowed invoice languages and a default invoice language if none match
|
* @todo Implement allowed invoice languages and a default invoice language if none match
|
||||||
|
|
@ -197,6 +202,7 @@ final class ApiBillController extends Controller
|
||||||
$bill->createdBy = new NullAccount($request->header->account);
|
$bill->createdBy = new NullAccount($request->header->account);
|
||||||
$bill->billDate = new \DateTime('now'); // @todo: Date of payment
|
$bill->billDate = new \DateTime('now'); // @todo: Date of payment
|
||||||
$bill->performanceDate = new \DateTime('now'); // @todo: Date of payment
|
$bill->performanceDate = new \DateTime('now'); // @todo: Date of payment
|
||||||
|
$bill->accountNumber = $client->number;
|
||||||
|
|
||||||
$bill->shipping = 0;
|
$bill->shipping = 0;
|
||||||
$bill->shippingText = '';
|
$bill->shippingText = '';
|
||||||
|
|
@ -204,6 +210,10 @@ final class ApiBillController extends Controller
|
||||||
$bill->payment = 0;
|
$bill->payment = 0;
|
||||||
$bill->paymentText = '';
|
$bill->paymentText = '';
|
||||||
|
|
||||||
|
$bill->type = BillTypeMapper::get()
|
||||||
|
->where('name', 'sales_invoice')
|
||||||
|
->execute();
|
||||||
|
|
||||||
// @todo: use bill and shipping address instead of main address if available
|
// @todo: use bill and shipping address instead of main address if available
|
||||||
$bill->client = $client;
|
$bill->client = $client;
|
||||||
$bill->billTo = $client->account->name1;
|
$bill->billTo = $client->account->name1;
|
||||||
|
|
@ -214,20 +224,60 @@ final class ApiBillController extends Controller
|
||||||
|
|
||||||
$bill->setCurrency(ISO4217CharEnum::_EUR);
|
$bill->setCurrency(ISO4217CharEnum::_EUR);
|
||||||
|
|
||||||
// @todo implement allowed invoice languages and a default invoice language if none match
|
/** @var \Model\Setting $settings */
|
||||||
// @todo implement client invoice langage (this would allow invoice langauges which are different from the invoice address)
|
$settings = $this->app->appSettings->get(null,
|
||||||
$bill->setLanguage(
|
SettingsEnum::VALID_BILL_LANGUAGES,
|
||||||
!\in_array(
|
unit: $this->app->unitId,
|
||||||
$client->mainAddress->getCountry(),
|
module: 'Admin'
|
||||||
[ISO3166TwoEnum::_DEU, ISO3166TwoEnum::_AUT]
|
|
||||||
)
|
|
||||||
? ISO639x1Enum::_EN
|
|
||||||
: ISO639x1Enum::_DE
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (empty($settings)) {
|
||||||
|
/** @var \Model\Setting $settings */
|
||||||
|
$settings = $this->app->appSettings->get(null,
|
||||||
|
SettingsEnum::VALID_BILL_LANGUAGES,
|
||||||
|
unit: null,
|
||||||
|
module: 'Admin'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$validLanguages = [];
|
||||||
|
if (!empty($settings)) {
|
||||||
|
$validLanguages = \json_decode($settings->content, true);
|
||||||
|
} else {
|
||||||
|
$validLanguages = [
|
||||||
|
ISO639x1Enum::_EN,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$billLanguage = $validLanguages[0];
|
||||||
|
|
||||||
|
$clientBillLanguage = $client->getAttribute('bill_language')?->value->getValue();
|
||||||
|
if (!empty($clientBillLanguage) && \in_array($clientBillLanguage, $validLanguages)) {
|
||||||
|
$billLanguage = $clientBillLanguage;
|
||||||
|
} else {
|
||||||
|
$clientLanguages = ISO639x1Enum::languageFromCountry($client->mainAddress->getCountry());
|
||||||
|
$clientLanguage = !empty($clientLanguages) ? $clientLanguages[0] : '';
|
||||||
|
|
||||||
|
if (\in_array($clientLanguage, $validLanguages)) {
|
||||||
|
$billLanguage = $clientLanguage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$bill->setLanguage($billLanguage);
|
||||||
|
|
||||||
return $bill;
|
return $bill;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function createBaseBillElement(Client $client, Item $item, Bill $bill, RequestAbstract $request) : BillElement
|
||||||
|
{
|
||||||
|
$taxCode = $this->app->moduleManager->get('Billing', 'ApiTax')->getTaxCodeFromClientItem($client, $item, $request->getCountry());
|
||||||
|
|
||||||
|
$element = BillElement::fromItem($item, $taxCode, $request->getDataInt('quantity') ?? 1);
|
||||||
|
$element->bill = $request->getDataInt('bill') ?? 0;
|
||||||
|
|
||||||
|
return $element;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to create a bill from request.
|
* Method to create a bill from request.
|
||||||
*
|
*
|
||||||
|
|
@ -271,23 +321,22 @@ final class ApiBillController extends Controller
|
||||||
$bill = new Bill();
|
$bill = new Bill();
|
||||||
$bill->createdBy = new NullAccount($request->header->account);
|
$bill->createdBy = new NullAccount($request->header->account);
|
||||||
$bill->type = $billType;
|
$bill->type = $billType;
|
||||||
$bill->numberFormat = $billType->numberFormat;
|
|
||||||
// @todo: use defaultInvoiceAddress or mainAddress. also consider to use billto1, billto2, billto3 (for multiple lines e.g. name2, fao etc.)
|
// @todo: use defaultInvoiceAddress or mainAddress. also consider to use billto1, billto2, billto3 (for multiple lines e.g. name2, fao etc.)
|
||||||
$bill->billTo = (string) ($request->getData('billto')
|
$bill->billTo = (string) ($request->getDataString('billto')
|
||||||
?? ($account->account->name1 . (!empty($account->account->name2)
|
?? ($account->account->name1 . (!empty($account->account->name2)
|
||||||
? ', ' . $account->account->name2
|
? ', ' . $account->account->name2
|
||||||
: ''
|
: ''
|
||||||
)));
|
)));
|
||||||
$bill->billAddress = (string) ($request->getData('billaddress') ?? $account->mainAddress->address);
|
$bill->billAddress = (string) ($request->getDataString('billaddress') ?? $account->mainAddress->address);
|
||||||
$bill->billZip = (string) ($request->getData('billtopostal') ?? $account->mainAddress->postal);
|
$bill->billZip = (string) ($request->getDataString('billtopostal') ?? $account->mainAddress->postal);
|
||||||
$bill->billCity = (string) ($request->getData('billtocity') ?? $account->mainAddress->city);
|
$bill->billCity = (string) ($request->getDataString('billtocity') ?? $account->mainAddress->city);
|
||||||
$bill->billCountry = (string) (
|
$bill->billCountry = (string) (
|
||||||
$request->getData('billtocountry') ?? (
|
$request->getDataString('billtocountry') ?? (
|
||||||
($country = $account->mainAddress->getCountry()) === ISO3166TwoEnum::_XXX ? '' : $country)
|
($country = $account->mainAddress->getCountry()) === ISO3166TwoEnum::_XXX ? '' : $country)
|
||||||
);
|
);
|
||||||
$bill->client = !$request->hasData('client') ? null : $account;
|
$bill->client = !$request->hasData('client') ? null : $account;
|
||||||
$bill->supplier = !$request->hasData('supplier') ? null : $account;
|
$bill->supplier = !$request->hasData('supplier') ? null : $account;
|
||||||
$bill->performanceDate = new \DateTime($request->getData('performancedate') ?? 'now');
|
$bill->performanceDate = new \DateTime($request->getDataString('performancedate') ?? 'now');
|
||||||
$bill->setStatus($request->getDataInt('status') ?? BillStatus::ACTIVE);
|
$bill->setStatus($request->getDataInt('status') ?? BillStatus::ACTIVE);
|
||||||
|
|
||||||
return $bill;
|
return $bill;
|
||||||
|
|
@ -305,11 +354,11 @@ final class ApiBillController extends Controller
|
||||||
private function validateBillCreate(RequestAbstract $request) : array
|
private function validateBillCreate(RequestAbstract $request) : array
|
||||||
{
|
{
|
||||||
$val = [];
|
$val = [];
|
||||||
if (($val['client/supplier'] = (empty($request->getData('client'))
|
if (($val['client/supplier'] = (!$request->hasData('client')
|
||||||
&& (empty($request->getData('supplier'))
|
&& (!$request->hasData('supplier')
|
||||||
&& ($request->getDataInt('supplier') ?? -1) !== 0)
|
&& ($request->getDataInt('supplier') ?? -1) !== 0)
|
||||||
))
|
))
|
||||||
|| ($val['type'] = (empty($request->getData('type'))))
|
|| ($val['type'] = (!$request->hasData('type')))
|
||||||
) {
|
) {
|
||||||
return $val;
|
return $val;
|
||||||
}
|
}
|
||||||
|
|
@ -456,8 +505,8 @@ final class ApiBillController extends Controller
|
||||||
private function validateMediaAddToBill(RequestAbstract $request) : array
|
private function validateMediaAddToBill(RequestAbstract $request) : array
|
||||||
{
|
{
|
||||||
$val = [];
|
$val = [];
|
||||||
if (($val['media'] = (empty($request->getData('media')) && empty($request->getFiles())))
|
if (($val['media'] = (!$request->hasData('media') && empty($request->getFiles())))
|
||||||
|| ($val['bill'] = empty($request->getData('bill')))
|
|| ($val['bill'] = !$request->hasData('bill'))
|
||||||
) {
|
) {
|
||||||
return $val;
|
return $val;
|
||||||
}
|
}
|
||||||
|
|
@ -487,12 +536,20 @@ final class ApiBillController extends Controller
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$element = $this->createBillElementFromRequest($request, $response, $data);
|
/** @var \Modules\Billing\Models\Bill $old */
|
||||||
|
$old = BillMapper::get()
|
||||||
|
->with('client')
|
||||||
|
->with('client/attributes')
|
||||||
|
->with('client/attributes/type')
|
||||||
|
->with('client/attributes/value')
|
||||||
|
->where('id', $request->getDataInt('bill') ?? 0)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$element = $this->createBillElementFromRequest($request, $response, $old, $data);
|
||||||
$this->createModel($request->header->account, $element, BillElementMapper::class, 'bill_element', $request->getOrigin());
|
$this->createModel($request->header->account, $element, BillElementMapper::class, 'bill_element', $request->getOrigin());
|
||||||
|
|
||||||
/** @var \Modules\Billing\Models\Bill $old */
|
$new = clone $old;
|
||||||
$old = BillMapper::get()->where('id', $element->bill)->execute();
|
$new->addElement($element);
|
||||||
$new = $this->updateBillWithBillElement(clone $old, $element, 1);
|
|
||||||
$this->updateModel($request->header->account, $old, $new, BillMapper::class, 'bill_element', $request->getOrigin());
|
$this->updateModel($request->header->account, $old, $new, BillMapper::class, 'bill_element', $request->getOrigin());
|
||||||
|
|
||||||
$this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Bill element', 'Bill element successfully created.', $element);
|
$this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Bill element', 'Bill element successfully created.', $element);
|
||||||
|
|
@ -508,74 +565,32 @@ final class ApiBillController extends Controller
|
||||||
* @return BillElement
|
* @return BillElement
|
||||||
*
|
*
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
* @todo in the database the customer localized version should be stored because this is the version which went out
|
|
||||||
*/
|
*/
|
||||||
public function createBillElementFromRequest(RequestAbstract $request, ResponseAbstract $response, $data = null) : BillElement
|
private function createBillElementFromRequest(RequestAbstract $request, ResponseAbstract $response, Bill $bill, $data = null) : BillElement
|
||||||
{
|
{
|
||||||
$element = new BillElement();
|
|
||||||
$element->bill = (int) $request->getData('bill');
|
|
||||||
$element->item = $request->getDataInt('item') ?? 0;
|
|
||||||
|
|
||||||
if ($element->item === null) {
|
|
||||||
return $element;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var \Modules\ItemManagement\Models\Item $item */
|
/** @var \Modules\ItemManagement\Models\Item $item */
|
||||||
$item = ItemMapper::get()
|
$item = ItemMapper::get()
|
||||||
|
->with('attributes')
|
||||||
|
->with('attributes/type')
|
||||||
|
->with('attributes/value')
|
||||||
->with('l11n')
|
->with('l11n')
|
||||||
->with('l11n/type')
|
->with('l11n/type')
|
||||||
->where('id', $element->item)
|
->where('id', $request->getDataInt('item') ?? 0)
|
||||||
->where('l11n/type/title', ['name1', 'name2', 'name3'], 'IN')
|
->where('l11n/type/title', ['name1', 'name2', 'name3'], 'IN')
|
||||||
->where('l11n/language', $response->getLanguage())
|
->where('l11n/language', $bill->getLanguage())
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
$element->itemNumber = $item->number;
|
$element = $this->createBaseBillElement($bill->client, $item, $bill, $request);
|
||||||
$element->itemName = $item->getL11n('name1')->description;
|
$element->bill = $bill->getId();
|
||||||
$element->quantity = $request->getDataInt('quantity') ?? 0;
|
|
||||||
|
|
||||||
$element->singleSalesPriceNet = new Money($request->getDataInt('singlesalespricenet') ?? $item->salesPrice->getInt());
|
|
||||||
$element->totalSalesPriceNet = clone $element->singleSalesPriceNet;
|
|
||||||
$element->totalSalesPriceNet->mult($element->quantity);
|
|
||||||
|
|
||||||
// discounts
|
// discounts
|
||||||
if ($request->getData('discount_percentage') !== null) {
|
if ($request->getData('discount_percentage') !== null) {
|
||||||
$discount = (int) $request->getData('discount_percentage');
|
// @todo: implement a addDiscount function
|
||||||
|
|
||||||
$element->singleSalesPriceNet
|
|
||||||
->sub((int) ($element->singleSalesPriceNet->getInt() / 100 * $discount));
|
|
||||||
|
|
||||||
$element->totalSalesPriceNet
|
|
||||||
->sub((int) ($element->totalSalesPriceNet->getInt() / 100 * $discount));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$element->singlePurchasePriceNet = new Money($item->purchasePrice->getInt());
|
|
||||||
$element->totalPurchasePriceNet = clone $element->singlePurchasePriceNet;
|
|
||||||
$element->totalPurchasePriceNet->mult($element->quantity);
|
|
||||||
|
|
||||||
return $element;
|
return $element;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to update a bill because of a changed bill element (add, remove, change) from request.
|
|
||||||
*
|
|
||||||
* @param Bill $bill Bill
|
|
||||||
* @param BillElement $element Bill element
|
|
||||||
* @param int $type Change type (0 = update, -1 = remove, +1 = add)
|
|
||||||
*
|
|
||||||
* @return Bill
|
|
||||||
*
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public function updateBillWithBillElement(Bill $bill, BillElement $element, int $type = 1) : Bill
|
|
||||||
{
|
|
||||||
if ($type === 1) {
|
|
||||||
$bill->netSales->add($element->totalSalesPriceNet);
|
|
||||||
$bill->netCosts->add($element->totalPurchasePriceNet);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $bill;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to validate bill element creation from request
|
* Method to validate bill element creation from request
|
||||||
*
|
*
|
||||||
|
|
@ -588,7 +603,7 @@ final class ApiBillController extends Controller
|
||||||
private function validateBillElementCreate(RequestAbstract $request) : array
|
private function validateBillElementCreate(RequestAbstract $request) : array
|
||||||
{
|
{
|
||||||
$val = [];
|
$val = [];
|
||||||
if (($val['bill'] = empty($request->getData('bill')))) {
|
if (($val['bill'] = !$request->hasData('bill'))) {
|
||||||
return $val;
|
return $val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -597,6 +612,14 @@ final class ApiBillController extends Controller
|
||||||
|
|
||||||
public function apiPreviewRender(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void
|
public function apiPreviewRender(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void
|
||||||
{
|
{
|
||||||
|
/** @var \Modules\Billing\Models\Bill $bill */
|
||||||
|
$bill = BillMapper::get()
|
||||||
|
->with('type')
|
||||||
|
->with('type/l11n')
|
||||||
|
->with('elements')
|
||||||
|
->where('id', $request->getDataInt('bill') ?? 0)
|
||||||
|
->execute();
|
||||||
|
|
||||||
Autoloader::addPath(__DIR__ . '/../../../Resources/');
|
Autoloader::addPath(__DIR__ . '/../../../Resources/');
|
||||||
|
|
||||||
$templateId = $request->getData('bill_template', 'int');
|
$templateId = $request->getData('bill_template', 'int');
|
||||||
|
|
@ -634,7 +657,7 @@ final class ApiBillController extends Controller
|
||||||
module: 'Admin'
|
module: 'Admin'
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($settings === false) {
|
if (empty($settings)) {
|
||||||
/** @var \Model\Setting[] $settings */
|
/** @var \Model\Setting[] $settings */
|
||||||
$settings = $this->app->appSettings->get(null,
|
$settings = $this->app->appSettings->get(null,
|
||||||
[
|
[
|
||||||
|
|
@ -661,49 +684,45 @@ final class ApiBillController extends Controller
|
||||||
$view->setData('defaultTemplates', $defaultTemplates);
|
$view->setData('defaultTemplates', $defaultTemplates);
|
||||||
$view->setData('defaultAssets', $defaultAssets);
|
$view->setData('defaultAssets', $defaultAssets);
|
||||||
|
|
||||||
|
$path = $this->createBillDir($bill);
|
||||||
|
$pdfDir = __DIR__ . '/../../../Modules/Media/Files' . $path;
|
||||||
|
|
||||||
$view->setData('bill', $bill);
|
$view->setData('bill', $bill);
|
||||||
$view->setData('path', $pdfDir . '/' . $request->getData('bill') . '.pdf');
|
$view->setData('path', $pdfDir . '/' .$bill->billDate->format('Y-m-d') . '_' . $bill->number . '.pdf');
|
||||||
|
|
||||||
$view->setData('bill_creator', $request->getData('bill_creator'));
|
$view->setData('bill_creator', $request->getDataString('bill_creator'));
|
||||||
$view->setData('bill_title', $request->getData('bill_title'));
|
$view->setData('bill_title', $request->getDataString('bill_title'));
|
||||||
$view->setData('bill_subtitle', $request->getData('bill_subtitle'));
|
$view->setData('bill_subtitle', $request->getDataString('bill_subtitle'));
|
||||||
$view->setData('keywords', $request->getData('keywords'));
|
$view->setData('keywords', $request->getDataString('keywords'));
|
||||||
$view->setData('bill_logo_name', $request->getData('bill_logo_name'));
|
$view->setData('bill_logo_name', $request->getDataString('bill_logo_name'));
|
||||||
$view->setData('bill_slogan', $request->getData('bill_slogan'));
|
$view->setData('bill_slogan', $request->getDataString('bill_slogan'));
|
||||||
|
|
||||||
$view->setData('legal_company_name', $request->getData('legal_company_name'));
|
$view->setData('legal_company_name', $request->getDataString('legal_company_name'));
|
||||||
$view->setData('bill_company_address', $request->getData('bill_company_address'));
|
$view->setData('bill_company_address', $request->getDataString('bill_company_address'));
|
||||||
$view->setData('bill_company_city', $request->getData('bill_company_city'));
|
$view->setData('bill_company_city', $request->getDataString('bill_company_city'));
|
||||||
$view->setData('bill_company_ceo', $request->getData('bill_company_ceo'));
|
$view->setData('bill_company_ceo', $request->getDataString('bill_company_ceo'));
|
||||||
$view->setData('bill_company_website', $request->getData('bill_company_website'));
|
$view->setData('bill_company_website', $request->getDataString('bill_company_website'));
|
||||||
$view->setData('bill_company_email', $request->getData('bill_company_email'));
|
$view->setData('bill_company_email', $request->getDataString('bill_company_email'));
|
||||||
$view->setData('bill_company_phone', $request->getData('bill_company_phone'));
|
$view->setData('bill_company_phone', $request->getDataString('bill_company_phone'));
|
||||||
|
|
||||||
$view->setData('bill_company_tax_office', $request->getData('bill_company_tax_office'));
|
$view->setData('bill_company_tax_office', $request->getDataString('bill_company_tax_office'));
|
||||||
$view->setData('bill_company_tax_id', $request->getData('bill_company_tax_id'));
|
$view->setData('bill_company_tax_id', $request->getDataString('bill_company_tax_id'));
|
||||||
$view->setData('bill_company_vat_id', $request->getData('bill_company_vat_id'));
|
$view->setData('bill_company_vat_id', $request->getDataString('bill_company_vat_id'));
|
||||||
|
|
||||||
$view->setData('bill_company_bank_name', $request->getData('bill_company_bank_name'));
|
$view->setData('bill_company_bank_name', $request->getDataString('bill_company_bank_name'));
|
||||||
$view->setData('bill_company_bic', $request->getData('bill_company_bic'));
|
$view->setData('bill_company_bic', $request->getDataString('bill_company_bic'));
|
||||||
$view->setData('bill_company_iban', $request->getData('bill_company_iban'));
|
$view->setData('bill_company_iban', $request->getDataString('bill_company_iban'));
|
||||||
|
|
||||||
$view->setData('bill_type_name', $request->getData('bill_type_name'));
|
$view->setData('bill_type_name', $request->getDataString('bill_type_name'));
|
||||||
|
|
||||||
$view->setData('bill_invoice_no', $request->getData('bill_invoice_no'));
|
$view->setData('bill_start_text', $request->getDataString('bill_start_text'));
|
||||||
$view->setData('bill_invoice_date', $request->getData('bill_invoice_date'));
|
$view->setData('bill_lines', $request->getDataString('bill_lines'));
|
||||||
$view->setData('bill_service_date', $request->getData('bill_service_date'));
|
$view->setData('bill_end_text', $request->getDataString('bill_end_text'));
|
||||||
$view->setData('bill_customer_no', $request->getData('bill_customer_no'));
|
|
||||||
$view->setData('bill_po', $request->getData('bill_po'));
|
|
||||||
$view->setData('bill_due_date', $request->getData('bill_due_date'));
|
|
||||||
|
|
||||||
$view->setData('bill_start_text', $request->getData('bill_start_text'));
|
$view->setData('bill_payment_terms', $request->getDataString('bill_payment_terms'));
|
||||||
$view->setData('bill_lines', $request->getData('bill_lines'));
|
$view->setData('bill_terms', $request->getDataString('bill_terms'));
|
||||||
$view->setData('bill_end_text', $request->getData('bill_end_text'));
|
$view->setData('bill_taxes', $request->getDataString('bill_taxes'));
|
||||||
|
$view->setData('bill_currency', $request->getDataString('bill_currency'));
|
||||||
$view->setData('bill_payment_terms', $request->getData('bill_payment_terms'));
|
|
||||||
$view->setData('bill_terms', $request->getData('bill_terms'));
|
|
||||||
$view->setData('bill_taxes', $request->getData('bill_taxes'));
|
|
||||||
$view->setData('bill_currency', $request->getData('bill_currency'));
|
|
||||||
|
|
||||||
$pdf = $view->render();
|
$pdf = $view->render();
|
||||||
|
|
||||||
|
|
@ -729,6 +748,8 @@ final class ApiBillController extends Controller
|
||||||
|
|
||||||
/** @var \Modules\Billing\Models\Bill $bill */
|
/** @var \Modules\Billing\Models\Bill $bill */
|
||||||
$bill = BillMapper::get()
|
$bill = BillMapper::get()
|
||||||
|
->with('type')
|
||||||
|
->with('type/l11n')
|
||||||
->with('elements')
|
->with('elements')
|
||||||
->where('id', $request->getDataInt('bill') ?? 0)
|
->where('id', $request->getDataInt('bill') ?? 0)
|
||||||
->execute();
|
->execute();
|
||||||
|
|
@ -766,7 +787,7 @@ final class ApiBillController extends Controller
|
||||||
module: 'Admin'
|
module: 'Admin'
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($settings === false) {
|
if (empty($settings)) {
|
||||||
/** @var \Model\Setting[] $settings */
|
/** @var \Model\Setting[] $settings */
|
||||||
$settings = $this->app->appSettings->get(null,
|
$settings = $this->app->appSettings->get(null,
|
||||||
[
|
[
|
||||||
|
|
@ -792,10 +813,9 @@ final class ApiBillController extends Controller
|
||||||
|
|
||||||
$view->setData('defaultTemplates', $defaultTemplates);
|
$view->setData('defaultTemplates', $defaultTemplates);
|
||||||
$view->setData('defaultAssets', $defaultAssets);
|
$view->setData('defaultAssets', $defaultAssets);
|
||||||
|
$view->setData('bill', $bill);
|
||||||
|
|
||||||
/**
|
// @todo: add bill data such as company name bank information, ..., etc.
|
||||||
@todo: pass data to bill
|
|
||||||
*/
|
|
||||||
|
|
||||||
$pdf = $view->render();
|
$pdf = $view->render();
|
||||||
|
|
||||||
|
|
@ -812,20 +832,22 @@ final class ApiBillController extends Controller
|
||||||
// @codeCoverageIgnoreEnd
|
// @codeCoverageIgnoreEnd
|
||||||
}
|
}
|
||||||
|
|
||||||
\file_put_contents($pdfDir . '/' . $request->getData('bill') . '.pdf', $pdf);
|
$billFileName = $bill->billDate->format('Y-m-d') . '_' . $bill->number . '.pdf';
|
||||||
if (!\is_file($pdfDir . '/' . $request->getData('bill') . '.pdf')) {
|
|
||||||
|
\file_put_contents($pdfDir . '/' . $billFileName, $pdf);
|
||||||
|
if (!\is_file($pdfDir . '/' . $billFileName)) {
|
||||||
$response->header->status = RequestStatusCode::R_400;
|
$response->header->status = RequestStatusCode::R_400;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$media = $this->app->moduleManager->get('Media')->createDbEntry(
|
$media = $this->app->moduleManager->get('Media', 'Api')->createDbEntry(
|
||||||
status: [
|
status: [
|
||||||
'status' => UploadStatus::OK,
|
'status' => UploadStatus::OK,
|
||||||
'name' => $request->getData('bill') . '.pdf',
|
'name' => $billFileName,
|
||||||
'path' => $pdfDir,
|
'path' => $pdfDir,
|
||||||
'filename' => $request->getData('bill') . '.pdf',
|
'filename' => $billFileName,
|
||||||
'size' => \filesize($pdfDir . '/' . $request->getData('bill') . '.pdf'),
|
'size' => \filesize($pdfDir . '/' . $billFileName),
|
||||||
'extension' => 'pdf',
|
'extension' => 'pdf',
|
||||||
],
|
],
|
||||||
account: $request->header->account,
|
account: $request->header->account,
|
||||||
|
|
@ -846,7 +868,14 @@ final class ApiBillController extends Controller
|
||||||
$request->getOrigin()
|
$request->getOrigin()
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->fillJsonResponse($request, $response, NotificationLevel::OK, 'PDF', 'Bill Pdf successfully created.', $media);
|
$this->fillJsonResponse(
|
||||||
|
$request,
|
||||||
|
$response,
|
||||||
|
NotificationLevel::OK,
|
||||||
|
'PDF',
|
||||||
|
'Bill Pdf successfully created.',
|
||||||
|
$media
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -897,7 +926,7 @@ final class ApiBillController extends Controller
|
||||||
private function validateNoteCreate(RequestAbstract $request) : array
|
private function validateNoteCreate(RequestAbstract $request) : array
|
||||||
{
|
{
|
||||||
$val = [];
|
$val = [];
|
||||||
if (($val['id'] = empty($request->getData('id')))) {
|
if (($val['id'] = !$request->hasData('id'))) {
|
||||||
return $val;
|
return $val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,8 +107,8 @@ final class ApiBillTypeController extends Controller
|
||||||
private function validateBillTypeCreate(RequestAbstract $request) : array
|
private function validateBillTypeCreate(RequestAbstract $request) : array
|
||||||
{
|
{
|
||||||
$val = [];
|
$val = [];
|
||||||
if (($val['title'] = empty($request->getData('title')))
|
if (($val['title'] = !$request->hasData('title'))
|
||||||
|| ($val['name'] = empty($request->getData('name')))
|
|| ($val['name'] = !$request->hasData('name'))
|
||||||
) {
|
) {
|
||||||
return $val;
|
return $val;
|
||||||
}
|
}
|
||||||
|
|
@ -176,8 +176,8 @@ final class ApiBillTypeController extends Controller
|
||||||
private function validateBillTypeL11nCreate(RequestAbstract $request) : array
|
private function validateBillTypeL11nCreate(RequestAbstract $request) : array
|
||||||
{
|
{
|
||||||
$val = [];
|
$val = [];
|
||||||
if (($val['title'] = empty($request->getData('title')))
|
if (($val['title'] = !$request->hasData('title'))
|
||||||
|| ($val['type'] = empty($request->getData('type')))
|
|| ($val['type'] = !$request->hasData('type'))
|
||||||
) {
|
) {
|
||||||
return $val;
|
return $val;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -205,13 +205,14 @@ final class ApiPriceController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get tax definition
|
// Get tax definition
|
||||||
$tax = ($request->getData('price_type', 'int') ?? PriceType::SALES)
|
/** @var \Modules\Billing\Models\Tax\TaxCombination $tax */
|
||||||
|
$tax = ($request->getDataInt('price_type') ?? PriceType::SALES) === PriceType::SALES
|
||||||
? TaxCombinationMapper::get()
|
? TaxCombinationMapper::get()
|
||||||
->where('itemCode', $request->getData('price_item'))
|
->where('itemCode', $request->getDataInt('price_item'))
|
||||||
->where('clientCode', $account->getAttribute('client_code')->getId())
|
->where('clientCode', $account->getAttribute('client_code')->getId())
|
||||||
->execute()
|
->execute()
|
||||||
: TaxCombinationMapper::get()
|
: TaxCombinationMapper::get()
|
||||||
->where('itemCode', $request->getData('price_item'))
|
->where('itemCode', $request->getDataInt('price_item'))
|
||||||
->where('supplierCode', $account->getAttribute('supplier_code')->getId())
|
->where('supplierCode', $account->getAttribute('supplier_code')->getId())
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
|
|
@ -287,9 +288,9 @@ final class ApiPriceController extends Controller
|
||||||
$price->discountPercentage = (int) $request->getData('discountPercentage');
|
$price->discountPercentage = (int) $request->getData('discountPercentage');
|
||||||
$price->bonus = (int) $request->getData('bonus');
|
$price->bonus = (int) $request->getData('bonus');
|
||||||
$price->multiply = $request->getDataBool('multiply') ?? false;
|
$price->multiply = $request->getDataBool('multiply') ?? false;
|
||||||
$price->currency = $request->getData('currency') ?? ISO4217CharEnum::_EUR;
|
$price->currency = $request->getDataString('currency') ?? ISO4217CharEnum::_EUR;
|
||||||
$price->start = $request->hasData('start') ? new \DateTime($request->getData('start')) : null;
|
$price->start = $request->hasData('start') ? new \DateTime($request->getDataString('start')) : null;
|
||||||
$price->end = $request->hasData('end') ? new \DateTime($request->getData('end')) : null;
|
$price->end = $request->hasData('end') ? new \DateTime($request->getDataString('end')) : null;
|
||||||
|
|
||||||
return $price;
|
return $price;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,12 @@ use Modules\ClientManagement\Models\Client;
|
||||||
use Modules\ClientManagement\Models\ClientAttributeTypeMapper;
|
use Modules\ClientManagement\Models\ClientAttributeTypeMapper;
|
||||||
use Modules\ClientManagement\Models\ClientAttributeValue;
|
use Modules\ClientManagement\Models\ClientAttributeValue;
|
||||||
use Modules\ClientManagement\Models\NullClientAttributeValue;
|
use Modules\ClientManagement\Models\NullClientAttributeValue;
|
||||||
|
use Modules\Finance\Models\NullTaxCode;
|
||||||
|
use Modules\Finance\Models\TaxCode;
|
||||||
|
use Modules\Finance\Models\TaxCodeMapper;
|
||||||
|
use Modules\ItemManagement\Models\Item;
|
||||||
use Modules\ItemManagement\Models\NullItemAttributeValue;
|
use Modules\ItemManagement\Models\NullItemAttributeValue;
|
||||||
|
use Modules\Organization\Models\UnitMapper;
|
||||||
use Modules\SupplierManagement\Models\NullSupplierAttributeValue;
|
use Modules\SupplierManagement\Models\NullSupplierAttributeValue;
|
||||||
use phpOMS\Localization\ISO3166CharEnum;
|
use phpOMS\Localization\ISO3166CharEnum;
|
||||||
use phpOMS\Message\Http\RequestStatusCode;
|
use phpOMS\Message\Http\RequestStatusCode;
|
||||||
|
|
@ -42,6 +47,55 @@ use phpOMS\Model\Message\FormValidation;
|
||||||
*/
|
*/
|
||||||
final class ApiTaxController extends Controller
|
final class ApiTaxController extends Controller
|
||||||
{
|
{
|
||||||
|
public function getTaxCodeFromClientItem(Client $client, Item $item, string $defaultCountry = '') : TaxCode
|
||||||
|
{
|
||||||
|
// @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
|
||||||
|
/** @var \Modules\Billing\Models\Tax\TaxCombination $taxCombination */
|
||||||
|
$taxCombination = TaxCombinationMapper::get()
|
||||||
|
->where('itemCode', $item->getAttribute('sales_tax_code')?->value->getId())
|
||||||
|
->where('clientCode', $client->getAttribute('sales_tax_code')?->value->getId())
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
/** @var \Modules\Finance\Models\TaxCode $taxCode */
|
||||||
|
$taxCode = TaxCodeMapper::get()
|
||||||
|
->where('abbr', $taxCombination->taxCode)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
// If now tax code could be found, the local tax code should be used.
|
||||||
|
if ($taxCode instanceof NullTaxCode) {
|
||||||
|
/** @var \Modules\Organization\Models\Unit $unit */
|
||||||
|
$unit = UnitMapper::get()
|
||||||
|
->with('mainAddress')
|
||||||
|
->where('id', $this->app->unitId)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
// Create dummy client
|
||||||
|
$client = new Client();
|
||||||
|
$client->mainAddress = $unit->mainAddress;
|
||||||
|
|
||||||
|
if (!empty($defaultCountry)) {
|
||||||
|
$client->mainAddress->setCountry($defaultCountry);
|
||||||
|
}
|
||||||
|
|
||||||
|
$taxCodeAttribute = $this->getClientTaxCode($client, $unit->mainAddress);
|
||||||
|
|
||||||
|
/** @var \Modules\Billing\Models\Tax\TaxCombination $taxCombination */
|
||||||
|
$t = $item->getAttribute('sales_tax_code');
|
||||||
|
$taxCombination = TaxCombinationMapper::get()
|
||||||
|
->where('itemCode', $item->getAttribute('sales_tax_code')?->value->getId())
|
||||||
|
->where('clientCode', $taxCodeAttribute->getId())
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
/** @var \Modules\Finance\Models\TaxCode $taxCode */
|
||||||
|
$taxCode = TaxCodeMapper::get()
|
||||||
|
->where('abbr', $taxCombination->taxCode)
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $taxCode;
|
||||||
|
}
|
||||||
|
|
||||||
public function apiTaxCombinationCreate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void
|
public function apiTaxCombinationCreate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void
|
||||||
{
|
{
|
||||||
if (!empty($val = $this->validateTaxCombinationCreate($request))) {
|
if (!empty($val = $this->validateTaxCombinationCreate($request))) {
|
||||||
|
|
@ -94,10 +148,10 @@ final class ApiTaxController extends Controller
|
||||||
private function validateTaxCombinationCreate(RequestAbstract $request) : array
|
private function validateTaxCombinationCreate(RequestAbstract $request) : array
|
||||||
{
|
{
|
||||||
$val = [];
|
$val = [];
|
||||||
if (($val['tax_type'] = empty($request->getData('tax_type')))
|
if (($val['tax_type'] = !$request->hasData('tax_type'))
|
||||||
|| ($val['tax_code'] = empty($request->getData('tax_code')))
|
|| ($val['tax_code'] = !$request->hasData('tax_code'))
|
||||||
|| ($val['item_code'] = empty($request->getData('item_code')))
|
|| ($val['item_code'] = !$request->hasData('item_code'))
|
||||||
|| ($val['account_code'] = empty($request->getData('account_code')))
|
|| ($val['account_code'] = !$request->hasData('account_code'))
|
||||||
) {
|
) {
|
||||||
return $val;
|
return $val;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ final class CliController extends Controller
|
||||||
/* Type */
|
/* Type */
|
||||||
$type = $this->findSupplierInvoiceType($content, $identifiers['type'], $language);
|
$type = $this->findSupplierInvoiceType($content, $identifiers['type'], $language);
|
||||||
|
|
||||||
/** @var \Modules\Billing\Models\BillType $billTye */
|
/** @var \Modules\Billing\Models\BillType $billType */
|
||||||
$billType = BillTypeMapper::get()
|
$billType = BillTypeMapper::get()
|
||||||
->where('name', $type)
|
->where('name', $type)
|
||||||
->execute();
|
->execute();
|
||||||
|
|
@ -274,7 +274,7 @@ final class CliController extends Controller
|
||||||
foreach ($lines as $row => $line) {
|
foreach ($lines as $row => $line) {
|
||||||
if (\preg_match($match, $line, $found) === 1) {
|
if (\preg_match($match, $line, $found) === 1) {
|
||||||
if ($row < $bestPos) {
|
if ($row < $bestPos) {
|
||||||
$bestPos = $row;
|
$bestPos = $row;
|
||||||
$bestMatch = \trim($found['bill_date']);
|
$bestMatch = \trim($found['bill_date']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -292,7 +292,7 @@ final class CliController extends Controller
|
||||||
* @param string[] $lines Bill lines
|
* @param string[] $lines Bill lines
|
||||||
* @param array $matches Gross match patterns
|
* @param array $matches Gross match patterns
|
||||||
*
|
*
|
||||||
* @return string
|
* @return int
|
||||||
*
|
*
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
|
|
@ -416,7 +416,7 @@ final class CliController extends Controller
|
||||||
|
|
||||||
foreach ($formats as $format) {
|
foreach ($formats as $format) {
|
||||||
if (($obj = \DateTime::createFromFormat($format, $date)) !== false) {
|
if (($obj = \DateTime::createFromFormat($format, $date)) !== false) {
|
||||||
return $obj;
|
return $obj === false ? null : $obj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ use Modules\Admin\Models\NullAccount;
|
||||||
use Modules\Billing\Models\Attribute\BillAttribute;
|
use Modules\Billing\Models\Attribute\BillAttribute;
|
||||||
use Modules\ClientManagement\Models\Client;
|
use Modules\ClientManagement\Models\Client;
|
||||||
use Modules\Editor\Models\EditorDoc;
|
use Modules\Editor\Models\EditorDoc;
|
||||||
use Modules\ItemManagement\Models\Item;
|
|
||||||
use Modules\Media\Models\Collection;
|
use Modules\Media\Models\Collection;
|
||||||
use Modules\Media\Models\Media;
|
use Modules\Media\Models\Media;
|
||||||
use Modules\Media\Models\NullMedia;
|
use Modules\Media\Models\NullMedia;
|
||||||
|
|
@ -56,14 +55,6 @@ class Bill implements \JsonSerializable
|
||||||
*/
|
*/
|
||||||
public string $number = '';
|
public string $number = '';
|
||||||
|
|
||||||
/**
|
|
||||||
* Number format ID.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public string $numberFormat = '';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bill type.
|
* Bill type.
|
||||||
*
|
*
|
||||||
|
|
@ -82,6 +73,8 @@ class Bill implements \JsonSerializable
|
||||||
*/
|
*/
|
||||||
private int $status = BillStatus::DRAFT;
|
private int $status = BillStatus::DRAFT;
|
||||||
|
|
||||||
|
private int $paymentStatus = BillPaymentStatus::UNPAID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bill created at.
|
* Bill created at.
|
||||||
*
|
*
|
||||||
|
|
@ -136,6 +129,8 @@ class Bill implements \JsonSerializable
|
||||||
|
|
||||||
public string $language = ISO639x1Enum::_EN;
|
public string $language = ISO639x1Enum::_EN;
|
||||||
|
|
||||||
|
public string $accountNumber = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receiver.
|
* Receiver.
|
||||||
*
|
*
|
||||||
|
|
@ -468,10 +463,10 @@ class Bill implements \JsonSerializable
|
||||||
$this->netDiscount = new Money(0);
|
$this->netDiscount = new Money(0);
|
||||||
$this->grossDiscount = new Money(0);
|
$this->grossDiscount = new Money(0);
|
||||||
|
|
||||||
$this->createdAt = new \DateTimeImmutable();
|
$this->createdAt = new \DateTimeImmutable();
|
||||||
$this->createdBy = new NullAccount();
|
$this->createdBy = new NullAccount();
|
||||||
$this->referral = new NullAccount();
|
$this->referral = new NullAccount();
|
||||||
$this->type = new NullBillType();
|
$this->type = new NullBillType();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -510,7 +505,7 @@ class Bill implements \JsonSerializable
|
||||||
$this->id,
|
$this->id,
|
||||||
$this->type->getId(),
|
$this->type->getId(),
|
||||||
],
|
],
|
||||||
$this->numberFormat
|
$this->type->numberFormat
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -569,7 +564,7 @@ class Bill implements \JsonSerializable
|
||||||
{
|
{
|
||||||
foreach ($this->attributes as $attribute) {
|
foreach ($this->attributes as $attribute) {
|
||||||
if ($attribute->type->name === $attrName) {
|
if ($attribute->type->name === $attrName) {
|
||||||
return $attribute->value;
|
return $attribute;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -602,6 +597,32 @@ class Bill implements \JsonSerializable
|
||||||
$this->status = $status;
|
$this->status = $status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get paymentStatus
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public function getPaymentStatus() : int
|
||||||
|
{
|
||||||
|
return $this->paymentStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set paymentStatus
|
||||||
|
*
|
||||||
|
* @param int $paymentStatus Status
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
public function setPaymentStatus(int $paymentStatus) : void
|
||||||
|
{
|
||||||
|
$this->paymentStatus = $paymentStatus;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set currency.
|
* Set currency.
|
||||||
*
|
*
|
||||||
|
|
@ -709,7 +730,7 @@ class Bill implements \JsonSerializable
|
||||||
/**
|
/**
|
||||||
* Get Bill elements.
|
* Get Bill elements.
|
||||||
*
|
*
|
||||||
* @return array
|
* @return BillElement[]
|
||||||
*
|
*
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
|
|
@ -740,7 +761,7 @@ class Bill implements \JsonSerializable
|
||||||
$this->netDiscount->add($element->totalDiscountP->getInt());
|
$this->netDiscount->add($element->totalDiscountP->getInt());
|
||||||
|
|
||||||
// @todo: Discount might be in quantities
|
// @todo: Discount might be in quantities
|
||||||
$this->grossDiscount->add((int) ($element->taxR * $element->totalDiscountP->getInt() / 1000));
|
$this->grossDiscount->add((int) ($element->taxR->getInt() * $element->totalDiscountP->getInt() / 10000));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -848,7 +869,6 @@ class Bill implements \JsonSerializable
|
||||||
return [
|
return [
|
||||||
'id' => $this->id,
|
'id' => $this->id,
|
||||||
'number' => $this->number,
|
'number' => $this->number,
|
||||||
'numberFormat' => $this->numberFormat,
|
|
||||||
'type' => $this->type,
|
'type' => $this->type,
|
||||||
'shipTo' => $this->shipTo,
|
'shipTo' => $this->shipTo,
|
||||||
'shipFAO' => $this->shipFAO,
|
'shipFAO' => $this->shipFAO,
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ class BillElement implements \JsonSerializable
|
||||||
|
|
||||||
public int $order = 0;
|
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 ?int $item = null;
|
||||||
|
|
||||||
public string $itemNumber = '';
|
public string $itemNumber = '';
|
||||||
|
|
@ -47,7 +48,7 @@ class BillElement implements \JsonSerializable
|
||||||
|
|
||||||
public string $itemDescription = '';
|
public string $itemDescription = '';
|
||||||
|
|
||||||
public int $quantity = 0;
|
protected int $quantity = 0;
|
||||||
|
|
||||||
public Money $singleSalesPriceNet;
|
public Money $singleSalesPriceNet;
|
||||||
|
|
||||||
|
|
@ -57,9 +58,9 @@ class BillElement implements \JsonSerializable
|
||||||
|
|
||||||
public Money $totalSalesPriceGross;
|
public Money $totalSalesPriceGross;
|
||||||
|
|
||||||
public ?FloatInt $singleDiscountP = null;
|
public Money $singleDiscountP;
|
||||||
|
|
||||||
public ?FloatInt $totalDiscountP = null;
|
public Money $totalDiscountP;
|
||||||
|
|
||||||
public ?FloatInt $singleDiscountR = null;
|
public ?FloatInt $singleDiscountR = null;
|
||||||
|
|
||||||
|
|
@ -91,19 +92,19 @@ class BillElement implements \JsonSerializable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tax amount
|
* Tax amount
|
||||||
*
|
*
|
||||||
* @var null|FloatInt
|
* @var Money
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
public ?FloatInt $taxP = null;
|
public Money $taxP;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tax percentage
|
* Tax percentage
|
||||||
*
|
*
|
||||||
* @var null|FloatInt
|
* @var null|FloatInt
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
public ?FloatInt $taxR = null;
|
public FloatInt $taxR;
|
||||||
|
|
||||||
public string $taxCode = '';
|
public string $taxCode = '';
|
||||||
|
|
||||||
|
|
@ -155,6 +156,12 @@ class BillElement implements \JsonSerializable
|
||||||
|
|
||||||
$this->totalProfitNet = new Money();
|
$this->totalProfitNet = new Money();
|
||||||
$this->totalProfitGross = new Money();
|
$this->totalProfitGross = new Money();
|
||||||
|
|
||||||
|
$this->singleDiscountP = new Money();
|
||||||
|
$this->totalDiscountP = new Money();
|
||||||
|
|
||||||
|
$this->taxP = new Money();
|
||||||
|
$this->taxR = new FloatInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -169,6 +176,21 @@ class BillElement implements \JsonSerializable
|
||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setQuantity(int $quantity) : void
|
||||||
|
{
|
||||||
|
if ($this->quantity === $quantity) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->quantity = $quantity;
|
||||||
|
// @todo: recalculate all the prices!!!
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQuantity() : int
|
||||||
|
{
|
||||||
|
return $this->quantity;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set item.
|
* Set item.
|
||||||
*
|
*
|
||||||
|
|
@ -183,14 +205,14 @@ class BillElement implements \JsonSerializable
|
||||||
$this->item = $item;
|
$this->item = $item;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function fromItem(Item $item, TaxCode $code) : self
|
public static function fromItem(Item $item, TaxCode $code, int $quantity = 1) : self
|
||||||
{
|
{
|
||||||
$element = new self();
|
$element = new self();
|
||||||
$element->item = $item->getId();
|
$element->item = $item->getId();
|
||||||
$element->itemNumber = $item->number;
|
$element->itemNumber = $item->number;
|
||||||
$element->itemName = $item->getL11n('name1')->description;
|
$element->itemName = $item->getL11n('name1')->description;
|
||||||
$element->itemDescription = $item->getL11n('description_short')->description;
|
$element->itemDescription = $item->getL11n('description_short')->description;
|
||||||
$element->quantity = 0;
|
$element->quantity = $quantity;
|
||||||
|
|
||||||
// @todo: Use pricing instead of the default sales price
|
// @todo: Use pricing instead of the default sales price
|
||||||
// @todo: discounts might be in quantities
|
// @todo: discounts might be in quantities
|
||||||
|
|
@ -201,19 +223,19 @@ class BillElement implements \JsonSerializable
|
||||||
$element->singlePurchasePriceNet->setInt($item->purchasePrice->getInt());
|
$element->singlePurchasePriceNet->setInt($item->purchasePrice->getInt());
|
||||||
$element->totalPurchasePriceNet->setInt($element->quantity * $item->purchasePrice->getInt());
|
$element->totalPurchasePriceNet->setInt($element->quantity * $item->purchasePrice->getInt());
|
||||||
|
|
||||||
$element->singleProfitNet->setInt($element->singleSalesPriceNet->getInt() - $element->singlePurchasePriceNet->getInt());
|
$element->singleProfitNet->setInt($element->singleSalesPriceNet->getInt() - $element->singlePurchasePriceNet->getInt());
|
||||||
$element->totalProfitNet->setInt($element->quantity * ($element->totalSalesPriceNet->getInt() - $element->totalPurchasePriceNet->getInt()));
|
$element->totalProfitNet->setInt($element->quantity * ($element->totalSalesPriceNet->getInt() - $element->totalPurchasePriceNet->getInt()));
|
||||||
|
|
||||||
$element->taxP = new FloatInt((int) (($code->percentageInvoice * $element->totalSalesPriceNet->getInt()) / 1000));
|
$element->taxP = new FloatInt((int) (($code->percentageInvoice * $element->totalSalesPriceNet->getInt()) / 10000));
|
||||||
$element->taxR = new FloatInt($code->percentageInvoice);
|
$element->taxR = new FloatInt($code->percentageInvoice);
|
||||||
$element->taxCode = $code->abbr;
|
$element->taxCode = $code->abbr;
|
||||||
|
|
||||||
$element->singleListPriceGross->setInt((int) ($element->singleListPriceNet->getInt() + $element->singleListPriceNet->getInt() * $element->taxR->getInt() / 1000));
|
$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() / 1000));
|
$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() / 1000));
|
$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() / 1000));
|
$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() / 1000));
|
$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() / 1000));
|
$element->totalPurchasePriceGross->setInt((int) ($element->totalPurchasePriceNet->getInt() + $element->totalPurchasePriceNet->getInt() * $element->taxR->getInt() / 10000));
|
||||||
|
|
||||||
$element->singleProfitGross->setInt($element->singleSalesPriceGross->getInt() - $element->singlePurchasePriceGross->getInt());
|
$element->singleProfitGross->setInt($element->singleSalesPriceGross->getInt() - $element->singlePurchasePriceGross->getInt());
|
||||||
$element->totalProfitGross->setInt($element->quantity * ($element->totalSalesPriceGross->getInt() - $element->totalPurchasePriceGross->getInt()));
|
$element->totalProfitGross->setInt($element->quantity * ($element->totalSalesPriceGross->getInt() - $element->totalPurchasePriceGross->getInt()));
|
||||||
|
|
|
||||||
|
|
@ -42,13 +42,13 @@ class BillMapper extends DataMapperFactory
|
||||||
public const COLUMNS = [
|
public const COLUMNS = [
|
||||||
'billing_bill_id' => ['name' => 'billing_bill_id', 'type' => 'int', 'internal' => 'id'],
|
'billing_bill_id' => ['name' => 'billing_bill_id', 'type' => 'int', 'internal' => 'id'],
|
||||||
'billing_bill_number' => ['name' => 'billing_bill_number', 'type' => 'string', 'internal' => 'number'],
|
'billing_bill_number' => ['name' => 'billing_bill_number', 'type' => 'string', 'internal' => 'number'],
|
||||||
'billing_bill_numberformat' => ['name' => 'billing_bill_numberformat', 'type' => 'string', 'internal' => 'numberFormat'],
|
|
||||||
'billing_bill_type' => ['name' => 'billing_bill_type', 'type' => 'int', 'internal' => 'type'],
|
'billing_bill_type' => ['name' => 'billing_bill_type', 'type' => 'int', 'internal' => 'type'],
|
||||||
'billing_bill_template' => ['name' => 'billing_bill_template', 'type' => 'int', 'internal' => 'template'],
|
'billing_bill_template' => ['name' => 'billing_bill_template', 'type' => 'int', 'internal' => 'template'],
|
||||||
'billing_bill_header' => ['name' => 'billing_bill_header', 'type' => 'string', 'internal' => 'header'],
|
'billing_bill_header' => ['name' => 'billing_bill_header', 'type' => 'string', 'internal' => 'header'],
|
||||||
'billing_bill_footer' => ['name' => 'billing_bill_footer', 'type' => 'string', 'internal' => 'footer'],
|
'billing_bill_footer' => ['name' => 'billing_bill_footer', 'type' => 'string', 'internal' => 'footer'],
|
||||||
'billing_bill_info' => ['name' => 'billing_bill_info', 'type' => 'string', 'internal' => 'info'],
|
'billing_bill_info' => ['name' => 'billing_bill_info', 'type' => 'string', 'internal' => 'info'],
|
||||||
'billing_bill_status' => ['name' => 'billing_bill_status', 'type' => 'int', 'internal' => 'status'],
|
'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_shipTo' => ['name' => 'billing_bill_shipTo', 'type' => 'string', 'internal' => 'shipTo'],
|
||||||
'billing_bill_shipFAO' => ['name' => 'billing_bill_shipFAO', 'type' => 'string', 'internal' => 'shipFAO'],
|
'billing_bill_shipFAO' => ['name' => 'billing_bill_shipFAO', 'type' => 'string', 'internal' => 'shipFAO'],
|
||||||
'billing_bill_shipAddr' => ['name' => 'billing_bill_shipAddr', 'type' => 'string', 'internal' => 'shipAddress'],
|
'billing_bill_shipAddr' => ['name' => 'billing_bill_shipAddr', 'type' => 'string', 'internal' => 'shipAddress'],
|
||||||
|
|
@ -80,6 +80,7 @@ class BillMapper extends DataMapperFactory
|
||||||
'billing_bill_paymentterms_text' => ['name' => 'billing_bill_paymentterms_text', 'type' => 'string', 'internal' => 'termsText'],
|
'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_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_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_client' => ['name' => 'billing_bill_client', 'type' => 'int', 'internal' => 'client'],
|
||||||
'billing_bill_supplier' => ['name' => 'billing_bill_supplier', 'type' => 'int', 'internal' => 'supplier'],
|
'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_created_by' => ['name' => 'billing_bill_created_by', 'type' => 'int', 'internal' => 'createdBy', 'readonly' => true],
|
||||||
|
|
|
||||||
34
Models/BillPaymentStatus.php
Normal file
34
Models/BillPaymentStatus.php
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Karaka
|
||||||
|
*
|
||||||
|
* 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\Stdlib\Base\Enum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status for external references
|
||||||
|
*
|
||||||
|
* @package Modules\Billing\Models
|
||||||
|
* @license OMS License 2.0
|
||||||
|
* @link https://jingga.app
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
abstract class BillPaymentStatus extends Enum
|
||||||
|
{
|
||||||
|
public const UNKNOWN = 0;
|
||||||
|
|
||||||
|
public const PAID = 1;
|
||||||
|
|
||||||
|
public const UNPAID = 2;
|
||||||
|
}
|
||||||
|
|
@ -15,7 +15,6 @@ declare(strict_types=1);
|
||||||
namespace Modules\Billing\Models;
|
namespace Modules\Billing\Models;
|
||||||
|
|
||||||
use Modules\Media\Models\Collection;
|
use Modules\Media\Models\Collection;
|
||||||
use Modules\Media\Models\NullCollection;
|
|
||||||
use phpOMS\Localization\BaseStringL11n;
|
use phpOMS\Localization\BaseStringL11n;
|
||||||
use phpOMS\Localization\ISO639x1Enum;
|
use phpOMS\Localization\ISO639x1Enum;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ final class BillTypeMapper extends DataMapperFactory
|
||||||
'external' => null,
|
'external' => null,
|
||||||
],
|
],
|
||||||
'templates' => [
|
'templates' => [
|
||||||
'mapper' => MediaMapper::class,
|
'mapper' => CollectionMapper::class,
|
||||||
'table' => 'billing_bill_type_media_rel',
|
'table' => 'billing_bill_type_media_rel',
|
||||||
'external' => 'billing_bill_type_media_rel_dst',
|
'external' => 'billing_bill_type_media_rel_dst',
|
||||||
'self' => 'billing_bill_type_media_rel_src',
|
'self' => 'billing_bill_type_media_rel_src',
|
||||||
|
|
|
||||||
|
|
@ -97,17 +97,17 @@ class Price implements \JsonSerializable
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->item = new NullItem();
|
$this->item = new NullItem();
|
||||||
$this->itemgroup = new NullItemAttributeValue();
|
$this->itemgroup = new NullItemAttributeValue();
|
||||||
$this->itemsegment = new NullItemAttributeValue();
|
$this->itemsegment = new NullItemAttributeValue();
|
||||||
$this->itemsection = new NullItemAttributeValue();
|
$this->itemsection = new NullItemAttributeValue();
|
||||||
$this->itemtype = new NullItemAttributeValue();
|
$this->itemtype = new NullItemAttributeValue();
|
||||||
|
|
||||||
$this->client = new NullClient();
|
$this->client = new NullClient();
|
||||||
$this->clientgroup = new NullClientAttributeValue();
|
$this->clientgroup = new NullClientAttributeValue();
|
||||||
$this->clientsegment = new NullClientAttributeValue();
|
$this->clientsegment = new NullClientAttributeValue();
|
||||||
$this->clientsection = new NullClientAttributeValue();
|
$this->clientsection = new NullClientAttributeValue();
|
||||||
$this->clienttype = new NullClientAttributeValue();
|
$this->clienttype = new NullClientAttributeValue();
|
||||||
|
|
||||||
$this->supplier = new NullSupplier();
|
$this->supplier = new NullSupplier();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,9 @@ use phpOMS\Stdlib\Base\Enum;
|
||||||
*/
|
*/
|
||||||
abstract class SettingsEnum extends Enum
|
abstract class SettingsEnum extends Enum
|
||||||
{
|
{
|
||||||
public const PREVIEW_MEDIA_TYPE = '1005100001_1'; // internally generated preview
|
public const PREVIEW_MEDIA_TYPE = '1005100001'; // internally generated preview
|
||||||
|
|
||||||
public const ORIGINAL_MEDIA_TYPE = '1005100001_2'; // original document (mostly supplier invoice/delivery note)
|
public const ORIGINAL_MEDIA_TYPE = '1005100002'; // original document (mostly supplier invoice/delivery note)
|
||||||
|
|
||||||
|
public const VALID_BILL_LANGUAGES = '1005100003'; // List of valid languages for bills
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ class TaxCombination implements \JsonSerializable
|
||||||
|
|
||||||
public string $taxCode = '';
|
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 int $taxType = BillTaxType::SALES;
|
public int $taxType = BillTaxType::SALES;
|
||||||
|
|
||||||
public string $account = '';
|
public string $account = '';
|
||||||
|
|
|
||||||
|
|
@ -787,7 +787,7 @@ echo $this->getData('nav')->render();
|
||||||
?>
|
?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><?= $values['month'] . '/' . \substr((string) $values['year'], -2); ?>
|
<td><?= $values['month'] . '/' . \substr((string) $values['year'], -2); ?>
|
||||||
<td><?= (new Money(((int) $values['net_sales']) / 1000))->getCurrency(); ?>
|
<td><?= (new Money(((int) $values['net_sales']) / 10000))->getCurrency(); ?>
|
||||||
<td><?= ((int) $values['customers']); ?>
|
<td><?= ((int) $values['customers']); ?>
|
||||||
<td><?= ((int) $values['customers']); ?>
|
<td><?= ((int) $values['customers']); ?>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
|
@ -910,7 +910,7 @@ echo $this->getData('nav')->render();
|
||||||
?>
|
?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><?= (string) $values['year']; ?>
|
<td><?= (string) $values['year']; ?>
|
||||||
<td><?= (new Money(((int) $values['net_sales']) / 1000))->getCurrency(); ?>
|
<td><?= (new Money(((int) $values['net_sales']) / 10000))->getCurrency(); ?>
|
||||||
<td><?= ((int) $values['customers']); ?>
|
<td><?= ((int) $values['customers']); ?>
|
||||||
<td><?= ((int) $values['customers']); ?>
|
<td><?= ((int) $values['customers']); ?>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
|
@ -1617,7 +1617,7 @@ echo $this->getData('nav')->render();
|
||||||
?>
|
?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><?= $values['month'] . '/' . \substr((string) $values['year'], -2); ?>
|
<td><?= $values['month'] . '/' . \substr((string) $values['year'], -2); ?>
|
||||||
<td><?= (new Money(((int) $values['net_sales']) / 1000))->getCurrency(); ?>
|
<td><?= (new Money(((int) $values['net_sales']) / 10000))->getCurrency(); ?>
|
||||||
<td><?= ((int) $values['customers']); ?>
|
<td><?= ((int) $values['customers']); ?>
|
||||||
<td><?= ((int) $values['customers']); ?>
|
<td><?= ((int) $values['customers']); ?>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
|
@ -1739,7 +1739,7 @@ echo $this->getData('nav')->render();
|
||||||
?>
|
?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><?= (string) $values['year']; ?>
|
<td><?= (string) $values['year']; ?>
|
||||||
<td><?= (new Money(((int) $values['net_sales']) / 1000))->getCurrency(); ?>
|
<td><?= (new Money(((int) $values['net_sales']) / 10000))->getCurrency(); ?>
|
||||||
<td><?= ((int) $values['customers']); ?>
|
<td><?= ((int) $values['customers']); ?>
|
||||||
<td><?= ((int) $values['customers']); ?>
|
<td><?= ((int) $values['customers']); ?>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
"SupplierManagement": "1.0.0"
|
"SupplierManagement": "1.0.0"
|
||||||
},
|
},
|
||||||
"providing": {
|
"providing": {
|
||||||
|
"Admin": "*",
|
||||||
"Navigation": "*",
|
"Navigation": "*",
|
||||||
"Media": "*",
|
"Media": "*",
|
||||||
"Workflow": "*"
|
"Workflow": "*"
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ final class ApiControllerTest extends \PHPUnit\Framework\TestCase
|
||||||
|
|
||||||
$permission = new AccountPermission();
|
$permission = new AccountPermission();
|
||||||
$permission->setUnit(1);
|
$permission->setUnit(1);
|
||||||
$permission->setApp('backend');
|
$permission->setApp(2);
|
||||||
$permission->setPermission(
|
$permission->setPermission(
|
||||||
PermissionType::READ
|
PermissionType::READ
|
||||||
| PermissionType::CREATE
|
| PermissionType::CREATE
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user