auto fixes + some impl.

This commit is contained in:
Dennis Eichhorn 2024-01-26 22:53:59 +00:00
parent d8cb2bcd64
commit ab013ca166
58 changed files with 1416 additions and 1271 deletions

View File

@ -73,8 +73,6 @@ $topPos = $pdf->getY();
// Set up default bill template
$billTypeName = \strtoupper($bill->type->getL11n());
// @todo depending on amount of lines, there is a solution (html, or use backtracking of tcpdf)
// Address
$pdf->setY(50);
$pdf->setFont('helvetica', '', 10);
@ -170,7 +168,7 @@ $header = [
$lang[$pdf->language]['Total'],
];
$lines = $bill->getElements();
$lines = $bill->elements;
// Header
$headerCount = \count($header);
@ -184,8 +182,8 @@ $first = true;
// Data
$fill = false;
foreach($lines as $line) {
// @todo add support for empty lines (row = line)
if (/*$row === null || */$first || $pdf->getY() > $pdf->getPageHeight() - 40) {
// @todo depending on amount of lines, there is a solution (html, or use backtracking of tcpdf)
if ($first || $pdf->getY() > $pdf->getPageHeight() - 40) {
$pdf->setFillColor(255, 162, 7);
$pdf->setTextColor(255);
$pdf->setDrawColor(255, 162, 7);
@ -209,24 +207,36 @@ foreach($lines as $line) {
$first = false;
}
// Discounts are shown below the original price -> additional line
// We don't want discount columns because that hints at customers they might be able to get discounts.
$lines = 1
+ ((int) ($line->discountQ->value > 0))
+ ((int) ($line->singleDiscountP->value > 0))
+ ((int) ($line->singleDiscountR->value > 0));
$tempY = $pdf->getY();
$pdf->writeHTMLCell($w[0], 10, null, null, $line->itemNumber . ' ' . $line->itemName, 0, 2, $fill);
//$pdf->writeHTMLCell($w[0], 10, null, null, $line->itemNumber . ' ' . $line->itemName, 0, 2, $fill);
$pdf->MultiCell($w[0], 10 * $lines, \trim($line->itemNumber . ' ' . $line->itemName), 0, 'L', $fill, 2, null, null, true, 0, true, true, 0, 'M', false);
$height = $pdf->getY() - $tempY;
$singleSalesPriceNet = Money::fromFloatInt($line->singleSalesPriceNet);
$totalSalesPriceNet = Money::fromFloatInt($line->totalSalesPriceNet);
$singleListPriceNet = Money::fromFloatInt($line->singleListPriceNet);
$totalSalesPriceNet = Money::fromFloatInt($line->totalSalesPriceNet);
$pdf->MultiCell($w[1], $height, (string) $line->getQuantity(), 0, 'L', $fill, 0, 15 + $w[0], $tempY, true, 0, false, true, 0, 'M', true);
$pdf->MultiCell($w[2], $height, $singleSalesPriceNet->getCurrency(2, symbol: ''), 0, 'L', $fill, 0, 15 + $w[0] + $w[1], $tempY, true, 0, false, true, 0, 'M', true);
$pdf->MultiCell($w[3], $height, $totalSalesPriceNet->getCurrency(2, symbol: ''), 0, 'L', $fill, 1, 15 + $w[0] + $w[1] + $w[2], $tempY, true, 0, false, true, 0, 'M', true);
if ($line->quantity->value === 0) {
$pdf->MultiCell($w[1] + $w[2] + $w[3], $height, '', 0, 'L', $fill, 0, 15 + $w[0], $tempY, true, 0, false, true, 0, 'M', true);
} else {
$pdf->MultiCell($w[1], $height, (string) $line->quantity->getAmount($line->container->quantityDecimals), 0, 'L', $fill, 0, 15 + $w[0], $tempY, true, 0, false, true, 0, 'M', true);
$pdf->MultiCell($w[2], $height, $singleListPriceNet->getCurrency(2, symbol: ''), 0, 'L', $fill, 0, 15 + $w[0] + $w[1], $tempY, true, 0, false, true, 0, 'M', true);
$pdf->MultiCell($w[3], $height, $totalSalesPriceNet->getCurrency(2, symbol: ''), 0, 'L', $fill, 1, 15 + $w[0] + $w[1] + $w[2], $tempY, true, 0, false, true, 0, 'M', true);
}
$fill = !$fill;
// get taxes
if (!isset($taxes[$line->taxR->getInt() / 100])) {
$taxes[$line->taxR->getInt() / 100] = $line->taxP;
if (!isset($taxes[$line->taxR->value / 10000])) {
$taxes[$line->taxR->value / 10000] = $line->taxP;
} else {
$taxes[$line->taxR->getInt() / 100]->add($line->taxP);
$taxes[$line->taxR->value / 10000]->add($line->taxP);
}
}

View File

@ -18,7 +18,6 @@ use Modules\Billing\Models\SettingsEnum;
use phpOMS\Application\ApplicationAbstract;
use phpOMS\Message\Http\HttpRequest;
use phpOMS\Message\Http\HttpResponse;
use phpOMS\Uri\HttpUri;
/**
* Media class.
@ -57,7 +56,7 @@ class Messages
];
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('settings', \json_encode($settings));

View File

@ -428,6 +428,12 @@
"type": "TINYINT(1)",
"null": false
},
"billing_type_accounting": {
"description": "Is this bill relevant for accounting",
"name": "billing_type_accounting",
"type": "TINYINT(1)",
"null": false
},
"billing_type_transfer_sign": {
"description": "1 = from->to direction, -1 = to->from direction = credit note",
"name": "billing_type_transfer_sign",
@ -553,17 +559,25 @@
},
"billing_bill_template": {
"name": "billing_bill_template",
"type": "INT",
"null": true,
"default": null,
"foreignTable": "media",
"foreignKey": "media_id"
"type": "TINYINT(1)",
"null": false
},
"billing_bill_archived": {
"name": "billing_bill_archived",
"type": "TINYINT(1)",
"null": false
},
"billing_bill_account_no": {
"name": "billing_bill_account_no",
"type": "VARCHAR(50)",
"null": false
},
"billing_bill_tax_type": {
"name": "billing_bill_tax_type",
"type": "INT",
"null": true,
"default": null
},
"billing_bill_supplier": {
"name": "billing_bill_supplier",
"type": "INT",
@ -736,6 +750,11 @@
"type": "BIGINT",
"null": false
},
"billing_bill_taxp": {
"name": "billing_bill_taxp",
"type": "BIGINT",
"null": false
},
"billing_bill_currency": {
"name": "billing_bill_currency",
"type": "VARCHAR(3)",
@ -749,6 +768,11 @@
"foreignTable": "language",
"foreignKey": "language_639_1"
},
"billing_bill_fiaccount": {
"name": "billing_bill_fiaccount",
"type": "VARCHAR(10)",
"null": false
},
"billing_bill_referral": {
"name": "billing_bill_referral",
"type": "INT",
@ -768,7 +792,36 @@
"type": "INT",
"null": false
},
"billing_bill_accsegment": {
"description": "attribute values",
"name": "billing_bill_accsegment",
"type": "INT",
"null": true,
"default": null
},
"billing_bill_accsection": {
"description": "attribute values",
"name": "billing_bill_accsection",
"type": "INT",
"null": true,
"default": null
},
"billing_bill_accgroup": {
"description": "attribute values",
"name": "billing_bill_accgroup",
"type": "INT",
"null": true,
"default": null
},
"billing_bill_acctype": {
"description": "attribute values",
"name": "billing_bill_acctype",
"type": "INT",
"null": true,
"default": null
},
"billing_bill_payment": {
"description": "should this handle the dues?",
"name": "billing_bill_payment",
"type": "INT",
"null": false
@ -906,6 +959,14 @@
"foreignTable": "itemmgmt_item",
"foreignKey": "itemmgmt_item_id"
},
"billing_bill_element_container": {
"name": "billing_bill_element_container",
"type": "INT",
"null": false,
"default": null,
"foreignTable": "itemmgmt_item_container",
"foreignKey": "itemmgmt_item_container_id"
},
"billing_bill_element_subscription": {
"name": "billing_bill_element_subscription",
"type": "INT",
@ -937,7 +998,7 @@
},
"billing_bill_element_quantity": {
"name": "billing_bill_element_quantity",
"type": "INT",
"type": "BIGINT",
"null": false
},
"billing_bill_element_single_netlistprice": {
@ -970,6 +1031,12 @@
"null": true,
"default": null
},
"billing_bill_element_single_effectivenetsalesprice": {
"name": "billing_bill_element_single_effectivenetsalesprice",
"type": "BIGINT",
"null": true,
"default": null
},
"billing_bill_element_single_grosssalesprice": {
"name": "billing_bill_element_single_grosssalesprice",
"type": "BIGINT",
@ -1108,6 +1175,51 @@
"null": true,
"default": null
},
"billing_bill_element_segment": {
"description": "attribute values",
"name": "billing_bill_element_segment",
"type": "INT",
"null": true,
"default": null,
"foreignTable": "itemmgmt_attr_value",
"foreignKey": "itemmgmt_attr_value_id"
},
"billing_bill_element_section": {
"description": "attribute values",
"name": "billing_bill_element_section",
"type": "INT",
"null": true,
"default": null,
"foreignTable": "itemmgmt_attr_value",
"foreignKey": "itemmgmt_attr_value_id"
},
"billing_bill_element_salesgroup": {
"description": "attribute values",
"name": "billing_bill_element_salesgroup",
"type": "INT",
"null": true,
"default": null,
"foreignTable": "itemmgmt_attr_value",
"foreignKey": "itemmgmt_attr_value_id"
},
"billing_bill_element_productgroup": {
"description": "attribute values",
"name": "billing_bill_element_productgroup",
"type": "INT",
"null": true,
"default": null,
"foreignTable": "itemmgmt_attr_value",
"foreignKey": "itemmgmt_attr_value_id"
},
"billing_bill_element_itemtype": {
"description": "attribute values",
"name": "billing_bill_element_itemtype",
"type": "INT",
"null": true,
"default": null,
"foreignTable": "itemmgmt_attr_value",
"foreignKey": "itemmgmt_attr_value_id"
},
"billing_bill_element_bill": {
"name": "billing_bill_element_bill",
"type": "INT",
@ -1115,9 +1227,24 @@
"foreignTable": "billing_bill",
"foreignKey": "billing_bill_id"
},
"billing_bill_element_fiaccount": {
"name": "billing_bill_element_fiaccount",
"type": "VARCHAR(10)",
"null": false
},
"billing_bill_element_costcenter": {
"name": "billing_bill_element_costcenter",
"type": "VARCHAR(10)",
"null": false
},
"billing_bill_element_costobject": {
"name": "billing_bill_element_costobject",
"type": "VARCHAR(10)",
"null": false
},
"billing_bill_element_promotion": {
"name": "billing_bill_element_promotion",
"type": "INT",
"type": "VARCHAR(10)",
"default": null,
"null": true
},
@ -1165,6 +1292,11 @@
"type": "TINYINT(1)",
"null": false
},
"billing_attr_type_internal": {
"name": "billing_attr_type_internal",
"type": "TINYINT(1)",
"null": false
},
"billing_attr_type_required": {
"description": "Every item must have this attribute type if set to true.",
"name": "billing_attr_type_required",

View File

@ -3,6 +3,8 @@
"name": "sales_offer",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 1,
"sign": 1,
"isAccounting": false,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -14,6 +16,8 @@
"name": "sales_order_confirmation",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 1,
"sign": 1,
"isAccounting": false,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -25,6 +29,8 @@
"name": "sales_delivery_note",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 1,
"sign": 1,
"isAccounting": false,
"transferStock": true,
"isTemplate": false,
"l11n": {
@ -36,6 +42,8 @@
"name": "sales_invoice",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 1,
"sign": 1,
"isAccounting": true,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -47,6 +55,8 @@
"name": "sales_proforma_invoice",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 1,
"sign": 1,
"isAccounting": false,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -58,6 +68,8 @@
"name": "sales_credit_note",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 1,
"sign": -1,
"isAccounting": true,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -69,6 +81,8 @@
"name": "sales_reverse_invoice",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 1,
"sign": -1,
"isAccounting": true,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -80,6 +94,8 @@
"name": "purchase_offer",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 2,
"sign": -1,
"isAccounting": false,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -87,10 +103,25 @@
"de": "Angebot"
}
},
{
"name": "purchase_order",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 2,
"sign": -1,
"isAccounting": false,
"transferStock": false,
"isTemplate": false,
"l11n": {
"en": "Order",
"de": "Bestellung"
}
},
{
"name": "purchase_order_confirmation",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 2,
"sign": -1,
"isAccounting": false,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -102,6 +133,8 @@
"name": "purchase_delivery_note",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 2,
"sign": -1,
"isAccounting": false,
"transferStock": true,
"isTemplate": false,
"l11n": {
@ -113,6 +146,8 @@
"name": "purchase_invoice",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 2,
"sign": -1,
"isAccounting": true,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -124,6 +159,8 @@
"name": "purchase_proforma_invoice",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 2,
"sign": -1,
"isAccounting": false,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -135,6 +172,8 @@
"name": "purchase_credit_note",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 2,
"sign": 1,
"isAccounting": true,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -146,6 +185,8 @@
"name": "purchase_reverse_invoice",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 2,
"sign": 1,
"isAccounting": true,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -157,6 +198,8 @@
"name": "stock_movement",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 4,
"sign": 1,
"isAccounting": false,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -165,20 +208,37 @@
}
},
{
"name": "stock_scrapping",
"name": "stock_decrease",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 4,
"transferStock": false,
"sign": -1,
"isAccounting": false,
"transferStock": true,
"isTemplate": false,
"l11n": {
"en": "Scrapping",
"de": "Verschrottung"
"en": "Stock Decrease",
"de": "Lagerausbuchung"
}
},
{
"name": "sales_subscritpion",
"name": "stock_increase",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 4,
"sign": 1,
"isAccounting": false,
"transferStock": true,
"isTemplate": false,
"l11n": {
"en": "Stock Increase",
"de": "Lagereinbuchung"
}
},
{
"name": "sales_subscription",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 1,
"sign": 1,
"isAccounting": true,
"transferStock": false,
"isTemplate": false,
"l11n": {
@ -187,36 +247,16 @@
}
},
{
"name": "sales_template",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 1,
"transferStock": false,
"isTemplate": true,
"l11n": {
"en": "Template",
"de": "Vorlage"
}
},
{
"name": "purchase_subscritpion",
"name": "purchase_subscription",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 2,
"sign": -1,
"isAccounting": true,
"transferStock": false,
"isTemplate": false,
"l11n": {
"en": "Subscription",
"de": "Abonnement"
}
},
{
"name": "purchase_template",
"numberFormat": "{y}{type}-{m}{sequence}",
"transferType": 2,
"transferStock": false,
"isTemplate": true,
"l11n": {
"en": "Template",
"de": "Vorlage"
}
}
]

View File

@ -24,7 +24,6 @@ use phpOMS\Message\Http\HttpRequest;
use phpOMS\Message\Http\HttpResponse;
use phpOMS\Module\InstallerAbstract;
use phpOMS\Module\ModuleInfo;
use phpOMS\Uri\HttpUri;
/**
* Installer class.
@ -107,7 +106,7 @@ final class Installer extends InstallerAbstract
}
/** @var array $terms */
$terms = \json_decode($fileContent, true);
$terms = \json_decode($fileContent, true);
$paymentTypeArray = self::createPaymentTerms($app, $terms);
/* Shipping terms */
@ -117,7 +116,7 @@ final class Installer extends InstallerAbstract
}
/** @var array $terms */
$terms = \json_decode($fileContent, true);
$terms = \json_decode($fileContent, true);
$shippingTypeArray = self::createShippingTerms($app, $terms);
}
@ -136,19 +135,21 @@ final class Installer extends InstallerAbstract
/** @var array $billAttrType */
$billAttrType = [];
/** @var \Modules\Billing\Controller\ApiController $module */
$module = $app->moduleManager->getModuleInstance('Billing');
/** @var \Modules\Billing\Controller\ApiAttributeController $module */
$module = $app->moduleManager->getModuleInstance('Billing', 'ApiAttribute');
/** @var array $attribute */
foreach ($attributes as $attribute) {
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('name', $attribute['name'] ?? '');
$request->setData('title', \reset($attribute['l11n']));
$request->setData('language', \array_keys($attribute['l11n'])[0] ?? 'en');
$request->setData('is_required', $attribute['is_required'] ?? false);
$request->setData('repeatable', $attribute['repeatable'] ?? false);
$request->setData('internal', $attribute['internal'] ?? false);
$request->setData('custom', $attribute['is_custom_allowed'] ?? false);
$request->setData('validation_pattern', $attribute['validation_pattern'] ?? '');
$request->setData('datatype', (int) $attribute['value_type']);
@ -173,7 +174,7 @@ final class Installer extends InstallerAbstract
}
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('title', $l11n);
@ -203,8 +204,8 @@ final class Installer extends InstallerAbstract
/** @var array<string, array> $billAttrValue */
$billAttrValue = [];
/** @var \Modules\Billing\Controller\ApiController $module */
$module = $app->moduleManager->getModuleInstance('Billing');
/** @var \Modules\Billing\Controller\ApiAttributeController $module */
$module = $app->moduleManager->getModuleInstance('Billing', 'ApiAttribute');
foreach ($attributes as $attribute) {
$billAttrValue[$attribute['name']] = [];
@ -212,7 +213,7 @@ final class Installer extends InstallerAbstract
/** @var array $value */
foreach ($attribute['values'] as $value) {
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('value', $value['value'] ?? '');
@ -246,7 +247,7 @@ final class Installer extends InstallerAbstract
}
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('title', $l11n);
@ -275,8 +276,8 @@ final class Installer extends InstallerAbstract
{
$result = [];
/** @var \Modules\Billing\Controller\ApiController $module */
$module = $app->moduleManager->getModuleInstance('Billing');
/** @var \Modules\Billing\Controller\ApiTaxController $module */
$module = $app->moduleManager->getModuleInstance('Billing', 'ApiTax');
/** @var \Modules\Attribute\Models\AttributeType $itemAttributeSales */
$itemAttributeSales = ItemAttributeTypeMapper::get()
@ -303,7 +304,7 @@ final class Installer extends InstallerAbstract
: $supplierAttributeSales->getDefaultByValue($tax['account_code']);
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('tax_type', $tax['type']);
@ -343,23 +344,25 @@ final class Installer extends InstallerAbstract
{
$billTypes = [];
/** @var \Modules\Billing\Controller\ApiController $module */
$module = $app->moduleManager->getModuleInstance('Billing');
/** @var \Modules\Billing\Controller\ApiBillTypeController $module */
$module = $app->moduleManager->getModuleInstance('Billing', 'ApiBillType');
// @todo allow multiple alternative bill templates
// @todo implement ordering of templates
foreach ($types as $type) {
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('name', $type['name'] ?? '');
$request->setData('title', \reset($type['l11n']));
$request->setData('language', \array_keys($type['l11n'])[0] ?? 'en');
$request->setData('number_format', $type['numberFormat'] ?? '{id}');
$request->setData('sign', $type['sign'] ?? 1);
$request->setData('transfer_stock', $type['transferStock'] ?? false);
$request->setData('is_template', $type['isTemplate'] ?? false);
$request->setData('is_accounting', $type['isAccounting'] ?? false);
$request->setData('transfer_type', $type['transferType'] ?? BillTransferType::SALES);
$request->setData('template', $template);
@ -384,7 +387,7 @@ final class Installer extends InstallerAbstract
}
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('title', $l11n);
@ -419,7 +422,7 @@ final class Installer extends InstallerAbstract
/** @var array $type */
foreach ($types as $type) {
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('name', $type['name'] ?? '');
@ -444,7 +447,7 @@ final class Installer extends InstallerAbstract
}
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('title', $l11n);
@ -479,7 +482,7 @@ final class Installer extends InstallerAbstract
/** @var array $type */
foreach ($types as $type) {
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('name', $type['name'] ?? '');
@ -504,7 +507,7 @@ final class Installer extends InstallerAbstract
}
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('title', $l11n);

View File

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

View File

@ -18,7 +18,7 @@ use phpOMS\Account\PermissionType;
use phpOMS\Router\RouteVerb;
return [
'^.*/bill/render\?.*$' => [
'^.*/bill/render(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\ApiBillController:apiMediaRender',
'verb' => RouteVerb::GET,
@ -29,7 +29,7 @@ return [
],
],
],
'^.*/bill/render/preview.*$' => [
'^.*/bill/render/preview(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\ApiBillController:apiPreviewRender',
'verb' => RouteVerb::GET,
@ -40,7 +40,7 @@ return [
],
],
],
'^.*/bill/price.*$' => [
'^.*/bill/price(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\ApiPriceController:apiPriceCreate',
'verb' => RouteVerb::GET,

View File

@ -18,7 +18,7 @@ use phpOMS\Account\PermissionType;
use phpOMS\Router\RouteVerb;
return [
'^.*/sales/bill/create.*$' => [
'^.*/sales/bill/create(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingSalesInvoiceCreate',
'verb' => RouteVerb::GET,
@ -29,7 +29,7 @@ return [
],
],
],
'^.*/sales/bill/list.*$' => [
'^.*/sales/bill/list(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingSalesList',
'verb' => RouteVerb::GET,
@ -40,7 +40,7 @@ return [
],
],
],
'^.*/sales/bill\?.*$' => [
'^.*/sales/bill(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingSalesInvoice',
'verb' => RouteVerb::GET,
@ -52,7 +52,7 @@ return [
],
],
'^.*/purchase/bill/create.*$' => [
'^.*/purchase/bill/create(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingPurchaseInvoiceCreate',
'verb' => RouteVerb::GET,
@ -63,7 +63,7 @@ return [
],
],
],
'^.*/purchase/bill/list.*$' => [
'^.*/purchase/bill/list(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingPurchaseList',
'verb' => RouteVerb::GET,
@ -74,7 +74,7 @@ return [
],
],
],
'^.*/purchase/bill\?.*$' => [
'^.*/purchase/bill(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingPurchaseInvoice',
'verb' => RouteVerb::GET,
@ -85,7 +85,7 @@ return [
],
],
],
'^.*/purchase/bill/upload\?.*$' => [
'^.*/purchase/bill/upload(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingPurchaseInvoiceUpload',
'verb' => RouteVerb::GET,
@ -97,7 +97,7 @@ return [
],
],
'^.*/warehouse/bill/create.*$' => [
'^.*/warehouse/bill/create(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingStockInvoiceCreate',
'verb' => RouteVerb::GET,
@ -108,7 +108,7 @@ return [
],
],
],
'^.*/warehouse/bill/list.*$' => [
'^.*/warehouse/bill/list(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingStockList',
'verb' => RouteVerb::GET,
@ -119,7 +119,7 @@ return [
],
],
],
'^.*/warehouse/bill\?.*$' => [
'^.*/warehouse/bill(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewBillingStockInvoice',
'verb' => RouteVerb::GET,
@ -131,7 +131,7 @@ return [
],
],
'^.*/private/purchase/recognition/dashboard.*$' => [
'^.*/private/purchase/recognition/dashboard(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewPrivatePurchaseBillDashboard',
'verb' => RouteVerb::GET,
@ -142,7 +142,7 @@ return [
],
],
],
'^.*/private/purchase/recognition/upload.*$' => [
'^.*/private/purchase/recognition/upload(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewPrivatePurchaseBillUpload',
'verb' => RouteVerb::GET,
@ -153,7 +153,7 @@ return [
],
],
],
'^.*/private/purchase/recognition/bill.*$' => [
'^.*/private/purchase/recognition/bill(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewPrivateBillingPurchaseInvoice',
'verb' => RouteVerb::GET,
@ -164,7 +164,7 @@ return [
],
],
],
'^.*/purchase/recognition/dashboard.*$' => [
'^.*/purchase/recognition/dashboard(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewPrivatePurchaseBillDashboard',
'verb' => RouteVerb::GET,
@ -175,7 +175,7 @@ return [
],
],
],
'^.*/purchase/recognition/upload.*$' => [
'^.*/purchase/recognition/upload(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewPrivatePurchaseBillUpload',
'verb' => RouteVerb::GET,
@ -186,7 +186,7 @@ return [
],
],
],
'^.*/purchase/recognition/bill.*$' => [
'^.*/purchase/recognition/bill(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewPrivateBillingPurchaseInvoice',
'verb' => RouteVerb::GET,
@ -198,7 +198,7 @@ return [
],
],
'^.*/bill/payment/list.*$' => [
'^.*/bill/payment/list(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewPaymentList',
'verb' => RouteVerb::GET,
@ -209,7 +209,7 @@ return [
],
],
],
'^.*/bill/payment/view.*$' => [
'^.*/bill/payment/view(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewPaymentView',
'verb' => RouteVerb::GET,
@ -220,7 +220,7 @@ return [
],
],
],
'^.*/bill/shipping/list.*$' => [
'^.*/bill/shipping/list(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewShippingList',
'verb' => RouteVerb::GET,
@ -231,7 +231,7 @@ return [
],
],
],
'^.*/bill/shipping/view.*$' => [
'^.*/bill/shipping/view(\?.*$|$)' => [
[
'dest' => '\Modules\Billing\Controller\BackendController:viewShippingView',
'verb' => RouteVerb::GET,

View File

@ -61,12 +61,15 @@ final class ApiAttributeController extends Controller
return;
}
$type = BillAttributeTypeMapper::get()->with('defaults')->where('id', (int) $request->getData('type'))->execute();
$type = BillAttributeTypeMapper::get()
->with('defaults')
->where('id', (int) $request->getData('type'))
->execute();
if (!$type->repeatable) {
$attr = BillAttributeMapper::count()
->with('type')
->where('type/id', (int) $request->getData('type'))
->where('type/id', $type->id)
->where('ref', (int) $request->getData('ref'))
->execute();
@ -164,13 +167,20 @@ final class ApiAttributeController extends Controller
->where('id', $request->getDataInt('type') ?? 0)
->execute();
if ($type->isInternal) {
$response->header->status = RequestStatusCode::R_403;
$this->createInvalidCreateResponse($request, $response, $val);
return;
}
$attrValue = $this->createAttributeValueFromRequest($request, $type);
$this->createModel($request->header->account, $attrValue, BillAttributeValueMapper::class, 'attr_value', $request->getOrigin());
if ($attrValue->isDefault) {
$this->createModelRelation(
$request->header->account,
(int) $request->getData('type'),
$type->id,
$attrValue->id,
BillAttributeTypeMapper::class, 'defaults', '', $request->getOrigin()
);

View File

@ -16,11 +16,15 @@ namespace Modules\Billing\Controller;
use Modules\Admin\Models\NullAccount;
use Modules\Admin\Models\SettingsEnum as AdminSettingsEnum;
use Modules\Attribute\Models\NullAttribute;
use Modules\Attribute\Models\NullAttributeType;
use Modules\Attribute\Models\NullAttributeValue;
use Modules\Billing\Models\Bill;
use Modules\Billing\Models\BillElement;
use Modules\Billing\Models\BillElementMapper;
use Modules\Billing\Models\BillMapper;
use Modules\Billing\Models\BillStatus;
use Modules\Billing\Models\BillTransferType;
use Modules\Billing\Models\BillTypeMapper;
use Modules\Billing\Models\NullBill;
use Modules\Billing\Models\NullBillElement;
@ -28,8 +32,10 @@ use Modules\Billing\Models\PermissionCategory;
use Modules\Billing\Models\SettingsEnum;
use Modules\ClientManagement\Models\Client;
use Modules\ClientManagement\Models\ClientMapper;
use Modules\ItemManagement\Models\Attribute\ItemAttributeMapper;
use Modules\ItemManagement\Models\Item;
use Modules\ItemManagement\Models\ItemMapper;
use Modules\ItemManagement\Models\NullContainer;
use Modules\Media\Models\CollectionMapper;
use Modules\Media\Models\Media;
use Modules\Media\Models\MediaMapper;
@ -46,12 +52,14 @@ use phpOMS\Autoloader;
use phpOMS\DataStorage\Database\Query\ColumnName;
use phpOMS\Localization\ISO4217CharEnum;
use phpOMS\Localization\ISO639x1Enum;
use phpOMS\Message\Http\HttpRequest;
use phpOMS\Message\Http\RequestStatusCode;
use phpOMS\Message\Mail\Email;
use phpOMS\Message\NotificationLevel;
use phpOMS\Message\RequestAbstract;
use phpOMS\Message\ResponseAbstract;
use phpOMS\Model\Message\FormValidation;
use phpOMS\Stdlib\Base\FloatInt;
use phpOMS\System\MimeType;
use phpOMS\Views\View;
@ -72,13 +80,17 @@ final class ApiBillController extends Controller
*
* @since 1.0.0
*/
public function __construct(ApplicationAbstract $app = null)
public function __construct(?ApplicationAbstract $app = null)
{
parent::__construct($app);
if ($this->app->moduleManager->isActive('WarehouseManagement')) {
$this->app->eventManager->importFromFile(__DIR__ . '/../../WarehouseManagement/Admin/Hooks/Manual.php');
}
if ($this->app->moduleManager->isActive('Accounting')) {
$this->app->eventManager->importFromFile(__DIR__ . '/../../Accounting/Admin/Hooks/Manual.php');
}
}
/**
@ -205,6 +217,13 @@ final class ApiBillController extends Controller
/**
* Create a base Bill object with default values
*
* Client attributes required:
* 'segment', 'section', 'client_group', 'client_type',
* 'sales_tax_code'
*
* Supplier attributes required:
* 'purchase_tax_code'
*
* @param Client|Supplier $account The client or supplier object for whom the bill is being created
* @param RequestAbstract $request The request object that contains the header account
*
@ -227,18 +246,24 @@ final class ApiBillController extends Controller
$bill->billDate = new \DateTime('now'); // @todo Date of payment
$bill->performanceDate = $request->getDataDateTime('performancedate') ?? new \DateTime('now'); // @todo Date of payment
$bill->accountNumber = $account->number;
$bill->setStatus($request->getDataInt('status') ?? BillStatus::DRAFT);
$bill->status = BillStatus::tryFromValue($request->getDataInt('status')) ?? BillStatus::DRAFT;
$bill->shippingTerms = null;
$bill->shippingText = '';
$bill->shippingTerms = null;
$bill->shippingText = '';
$bill->paymentTerms = null;
$bill->paymentText = '';
$bill->paymentTerms = null;
$bill->paymentText = '';
if ($account instanceof Client) {
$bill->client = $account;
$bill->client = $account;
$bill->accTaxCode = empty($temp = $bill->client->getAttribute('sales_tax_code')->value->id) ? null : $temp;
$bill->accSegment = empty($temp = $bill->client->getAttribute('segment')->value->id) ? null : $temp;
$bill->accSection = empty($temp = $bill->client->getAttribute('section')->value->id) ? null : $temp;
$bill->accGroup = empty($temp = $bill->client->getAttribute('client_group')->value->id) ? null : $temp;
$bill->accType = empty($temp = $bill->client->getAttribute('client_type')->value->id) ? null : $temp;
} else {
$bill->supplier = $account;
$bill->supplier = $account;
$bill->accTaxCode = empty($temp = $bill->supplier->getAttribute('purchase_tax_code')->value->id) ? null : $temp;
}
// @todo use bill and shipping address instead of main address if available
@ -246,9 +271,9 @@ final class ApiBillController extends Controller
$bill->billAddress = $request->getDataString('billaddress') ?? $account->mainAddress->address;
$bill->billCity = $request->getDataString('billtocity') ?? $account->mainAddress->city;
$bill->billZip = $request->getDataString('billtopostal') ?? $account->mainAddress->postal;
$bill->billCountry = $request->getDataString('billtocountry') ?? $account->mainAddress->getCountry();
$bill->billCountry = $request->getDataString('billtocountry') ?? $account->mainAddress->country;
$bill->setCurrency(ISO4217CharEnum::_EUR);
$bill->currency = ISO4217CharEnum::_EUR;
/** @var \Model\Setting $settings */
$settings = $this->app->appSettings->get(null,
@ -283,7 +308,7 @@ final class ApiBillController extends Controller
if (!empty($accountBillLanguage) && \in_array($accountBillLanguage, $validLanguages)) {
$billLanguage = $accountBillLanguage;
} else {
$accountLanguages = ISO639x1Enum::languageFromCountry($account->mainAddress->getCountry());
$accountLanguages = ISO639x1Enum::languageFromCountry($account->mainAddress->country);
$accountLanguage = empty($accountLanguages) ? '' : $accountLanguages[0];
if (\in_array($accountLanguage, $validLanguages)) {
@ -312,7 +337,11 @@ final class ApiBillController extends Controller
/**
* Create a base BillElement object with default values
*
* @param Client $client The client object for whom the bill is being created
* Item attributes required:
* 'segment', 'section', 'sales_group', 'product_group', 'product_type',
* 'sales_tax_code', 'purchase_tax_code', 'costcenter', 'costobject',
* 'default_purchase_container', 'default_sales_container',
*
* @param Item $item The item object for which the bill element is being created
* @param Bill $bill The bill object for which the bill element is being created
* @param RequestAbstract $request The request object that contains the header account
@ -321,17 +350,94 @@ final class ApiBillController extends Controller
*
* @since 1.0.0
*/
public function createBaseBillElement(Client $client, Item $item, Bill $bill, RequestAbstract $request) : BillElement
public function createBaseBillElement(Item $item, Bill $bill, RequestAbstract $request) : BillElement
{
$taxCode = $this->app->moduleManager->get('Billing', 'ApiTax')
->getTaxCodeFromClientItem($client, $item, $request->header->l11n->country);
// Handle person tax code for finding tax combination below
$attr = new NullAttribute();
$attrType = new NullAttributeType();
$attrType->name = $bill->client !== null ? 'sales_tax_code' : 'purchase_tax_code';
$attrValue = new NullAttributeValue($bill->accTaxCode ?? 0);
$attr->type = $attrType;
$attr->value = $attrValue;
return BillElement::fromItem(
$container = $request->hasData('container') ? new NullContainer($request->getDataInt('container')) : null;
$attr = new NullAttribute();
if ($bill->type->transferType === BillTransferType::PURCHASE) {
$bill->supplier->attributes[] = $attr;
if ($container === null) {
$attr = $item->getAttribute('default_purchase_container');
if ($attr->id === 0) {
/** @var \Modules\Attribute\Models\Attribute $attr */
$attr = ItemAttributeMapper::get()
->with('type')
->with('value')
->where('ref', $item->id)
->where('type/name', 'default_purchase_container')
->execute();
}
}
} else {
$bill->client->attributes[] = $attr;
if ($container === null) {
$attr = $item->getAttribute('default_sales_container');
if ($attr->id === 0) {
/** @var \Modules\Attribute\Models\Attribute $attr */
$attr = ItemAttributeMapper::get()
->with('type')
->with('value')
->where('ref', $item->id)
->where('type/name', 'default_sales_container')
->execute();
}
}
}
$container = $container === null && $attr->id !== 0
? new NullContainer($attr->value->getValue())
: $container;
$taxCombination = $this->app->moduleManager->get('Billing', 'ApiTax')
->getTaxForPerson($bill->client, $bill->supplier, $item, $request->header->l11n->country);
$element = BillElement::fromItem(
$item,
$taxCode,
$request->getDataInt('quantity') ?? 1,
$bill->id
$taxCombination,
FloatInt::toInt($request->getDataString('quantity') ?? 1),
$bill->id,
$container
);
$element->itemSegment = empty($temp = $item->getAttribute('segment')->value->id) ? null : $temp;
$element->itemSection = empty($temp = $item->getAttribute('section')->value->id) ? null : $temp;
$element->itemSalesGroup = empty($temp = $item->getAttribute('sales_group')->value->id) ? null : $temp;
$element->itemProductGroup = empty($temp = $item->getAttribute('product_group')->value->id) ? null : $temp;
$element->itemType = empty($temp = $item->getAttribute('product_type')->value->id) ? null : $temp;
$internalRequest = new HttpRequest($request->uri);
$internalRequest->header->account = $request->header->account;
$price = $this->app->moduleManager->get('Billing', 'ApiPrice')->findBestPrice($internalRequest, $item, $bill->client, $bill->supplier);
$element->singleListPriceNet->value = $price['bestPrice']->value === 0
? $item->salesPrice->value
: $price['bestPrice']->value;
$element->singleSalesPriceNet->value = $price['bestActualPrice']->value === 0
? $item->salesPrice->value
: $price['bestActualPrice']->value;
$element->singleDiscountP->value = ($price['discountAmount']->value ?? 0) / ($element->quantity->value - $price['bonus']->value);
$element->totalDiscountP = $price['discountAmount'];
$element->singleDiscountR = $price['discountPercent'];
$element->discountQ = $price['bonus'];
$element->recalculatePrices();
return $element;
}
/**
@ -354,7 +460,14 @@ final class ApiBillController extends Controller
$account = ClientMapper::get()
->with('account')
->with('mainAddress')
->with('attributes')
->with('attributes/type')
->with('attributes/value')
->where('id', (int) $request->getData('client'))
->where('attributes/type/name', [
'segment', 'section', 'client_group', 'client_type',
'sales_tax_code',
], 'IN')
->execute();
} elseif (($request->getDataInt('supplier') ?? -1) === 0) {
/** @var \Modules\SupplierManagement\Models\Supplier $account */
@ -364,7 +477,13 @@ final class ApiBillController extends Controller
$account = SupplierMapper::get()
->with('account')
->with('mainAddress')
->with('attributes')
->with('attributes/type')
->with('attributes/value')
->where('id', (int) $request->getData('supplier'))
->where('attributes/type/name', [
'purchase_tax_code',
], 'IN')
->execute();
}
@ -673,9 +792,7 @@ final class ApiBillController extends Controller
/** @var \Modules\Billing\Models\Bill $old */
$old = BillMapper::get()
->with('client')
->with('client/attributes')
->with('client/attributes/type')
->with('client/attributes/value')
->with('supplier')
->where('id', $request->getDataInt('bill') ?? 0)
->execute();
@ -691,7 +808,7 @@ final class ApiBillController extends Controller
$new = clone $old;
$new->addElement($element);
$this->updateModel($request->header->account, $old, $new, BillMapper::class, 'bill_element', $request->getOrigin());
$this->updateModel($request->header->account, $old, $new, BillMapper::class, 'bill', $request->getOrigin());
$this->createStandardCreateResponse($request, $response, $element);
}
@ -709,6 +826,8 @@ final class ApiBillController extends Controller
*/
private function createBillElementFromRequest(RequestAbstract $request, ResponseAbstract $response, Bill $bill, $data = null) : BillElement
{
// @todo handle text element
/** @var \Modules\ItemManagement\Models\Item $item */
$item = ItemMapper::get()
->with('attributes')
@ -717,6 +836,11 @@ final class ApiBillController extends Controller
->with('l11n')
->with('l11n/type')
->where('id', $request->getDataInt('item') ?? 0)
->where('attributes/type/name', [
'segment', 'section', 'sales_group', 'product_group', 'product_type',
'sales_tax_code', 'purchase_tax_code', 'costcenter', 'costobject',
'default_purchase_container', 'default_sales_container',
], 'IN')
->where('l11n/type/title', ['name1', 'name2', 'name3'], 'IN')
->where('l11n/language', $bill->language)
->execute();
@ -725,16 +849,9 @@ final class ApiBillController extends Controller
return new NullBillElement();
}
$element = $this->createBaseBillElement($bill->client, $item, $bill, $request);
$element = $this->createBaseBillElement($item, $bill, $request);
$element->bill = new NullBill($bill->id);
// discounts
// @todo implement a addDiscount function
/*
if ($request->getData('discount_percentage') !== null) {
}
*/
return $element;
}
@ -796,6 +913,7 @@ final class ApiBillController extends Controller
/** @var \Modules\Billing\Models\Bill $bill */
$bill = BillMapper::get()
->with('elements')
->with('elements/container')
->where('id', $request->getDataInt('bill') ?? 0)
->execute();
@ -849,7 +967,7 @@ final class ApiBillController extends Controller
->where('id', [
(int) $settings[AdminSettingsEnum::DEFAULT_TEMPLATES]->content,
(int) $settings[AdminSettingsEnum::DEFAULT_ASSETS]->content,
$templateId
$templateId,
], 'IN')
->execute();
@ -940,12 +1058,23 @@ final class ApiBillController extends Controller
/** @var \Modules\Billing\Models\Bill $bill */
$bill = BillMapper::get()
->with('elements')
->with('elements/container')
->with('type')
->with('type/l11n')
->where('id', $request->getDataInt('bill') ?? 0)
->where('type/l11n/language', new ColumnName(BillMapper::getColumnByMember('language')))
->execute();
$this->app->eventManager->triggerSimilar('PRE:Module:' . self::NAME . '-bill-finalize', '', [
$request->header->account,
null, $bill,
null, self::NAME . '-bill-finalize',
self::NAME,
(string) $bill->id,
null,
$request->getOrigin(),
]);
// Handle PDF generation
$templateId = $request->getDataInt('bill_template') ?? $bill->type->defaultTemplate?->id ?? 0;
@ -981,7 +1110,7 @@ final class ApiBillController extends Controller
->where('id', [
(int) $settings[AdminSettingsEnum::DEFAULT_TEMPLATES]->content,
(int) $settings[AdminSettingsEnum::DEFAULT_ASSETS]->content,
$templateId
$templateId,
], 'IN')
->execute();

View File

@ -75,11 +75,16 @@ final class ApiBillTypeController extends Controller
private function createBillTypeFromRequest(RequestAbstract $request) : BillType
{
$billType = new BillType($request->getDataString('name') ?? '');
$billType->setL11n($request->getDataString('title') ?? '', $request->getDataString('language') ?? ISO639x1Enum::_EN);
$billType->setL11n(
$request->getDataString('title') ?? '',
ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? ISO639x1Enum::_EN
);
$billType->numberFormat = $request->getDataString('number_format') ?? '{id}';
$billType->sign = $request->getDataInt('sign') ?? 1;
$billType->transferStock = $request->getDataBool('transfer_stock') ?? false;
$billType->isTemplate = $request->getDataBool('is_template') ?? false;
$billType->transferType = $request->getDataInt('transfer_type') ?? BillTransferType::SALES;
$billType->isAccounting = $request->getDataBool('is_accounting') ?? false;
$billType->transferType = BillTransferType::tryFromValue($request->getDataInt('transfer_type')) ?? BillTransferType::SALES;
$billType->defaultTemplate = $request->hasData('template')
? new NullCollection((int) $request->getData('template'))
: null;
@ -150,12 +155,10 @@ final class ApiBillTypeController extends Controller
*/
private function createBillTypeL11nFromRequest(RequestAbstract $request) : BaseStringL11n
{
$billTypeL11n = new BaseStringL11n();
$billTypeL11n->ref = $request->getDataInt('type') ?? 0;
$billTypeL11n->setLanguage(
$request->getDataString('language') ?? $request->header->l11n->language
);
$billTypeL11n->content = $request->getDataString('title') ?? '';
$billTypeL11n = new BaseStringL11n();
$billTypeL11n->ref = $request->getDataInt('type') ?? 0;
$billTypeL11n->language = ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? $request->header->l11n->language;
$billTypeL11n->content = $request->getDataString('title') ?? '';
return $billTypeL11n;
}
@ -228,7 +231,8 @@ final class ApiBillTypeController extends Controller
$new->numberFormat = $request->getDataString('number_format') ?? $new->numberFormat;
$new->transferStock = $request->getDataBool('transfer_stock') ?? $new->transferStock;
$new->isTemplate = $request->getDataBool('is_template') ?? $new->isTemplate;
$new->transferType = $request->getDataInt('transfer_type') ?? $new->transferType;
$new->isAccounting = $request->getDataBool('is_accounting') ?? $new->isAccounting;
$new->transferType = BillTransferType::tryFromValue($request->getDataInt('transfer_type')) ?? $new->transferType;
$new->defaultTemplate = $request->hasData('template')
? new NullCollection((int) $request->getData('template'))
: $new->defaultTemplate;
@ -346,11 +350,9 @@ final class ApiBillTypeController extends Controller
*/
public function updateBillTypeL11nFromRequest(RequestAbstract $request, BaseStringL11n $new) : BaseStringL11n
{
$new->ref = $request->getDataInt('type') ?? $new->ref;
$new->setLanguage(
$request->getDataString('language') ?? $new->language
);
$new->content = $request->getDataString('title') ?? $new->content;
$new->ref = $request->getDataInt('type') ?? $new->ref;
$new->language = ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? $new->language;
$new->content = $request->getDataString('title') ?? $new->content;
return $new;
}

View File

@ -36,347 +36,6 @@ use phpOMS\Message\ResponseAbstract;
*/
final class ApiController extends Controller
{
/**
* Api method to update a bill
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiBillUpdate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiBill')->apiBillUpdate($request, $response, $data);
}
/**
* Api method to create a bill
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiBillCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiBill')->apiBillCreate($request, $response, $data);
}
/**
* Api method to create a bill
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiMediaAddToBill(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiBill')->apiMediaAddToBill($request, $response, $data);
}
/**
* Api method to create a bill element
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiBillElementCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiBill')->apiBillElementCreate($request, $response, $data);
}
/**
* Api method to create a bill preview
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiPreviewRender(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiBill')->apiPreviewRender($request, $response, $data);
}
/**
* Api method to create and archive a bill
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiBillPdfArchiveCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiBill')->apiBillPdfArchiveCreate($request, $response, $data);
}
/**
* Api method to create a bill
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiBillPdfCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiBill')->apiBillPdfCreate($request, $response, $data);
}
/**
* Api method to create bill files
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiNoteCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiBill')->apiNoteCreate($request, $response, $data);
}
/**
* Api method to create bill files
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiSupplierBillUpload(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiPurchase')->apiSupplierBillUpload($request, $response, $data);
}
/**
* Api method to create item bill type
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiBillTypeCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiBillType')->apiBillTypeCreate($request, $response, $data);
}
/**
* Api method to create item attribute l11n
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiBillTypeL11nCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiBillType')->apiBillTypeL11nCreate($request, $response, $data);
}
/**
* Api method to create item bill type
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiTaxCombinationCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiTax')->apiTaxCombinationCreate($request, $response, $data);
}
/**
* Api method to create item bill type
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiPriceCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiPrice')->apiPriceCreate($request, $response, $data);
}
/**
* Api method to create item attribute
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiBillAttributeCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiAttribute')->apiBillAttributeCreate($request, $response, $data);
}
/**
* Api method to create bill attribute l11n
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiBillAttributeTypeL11nCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiAttribute')->apiBillAttributeTypeL11nCreate($request, $response, $data);
}
/**
* Api method to create bill attribute type
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiBillAttributeTypeCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiAttribute')->apiBillAttributeTypeCreate($request, $response, $data);
}
/**
* Api method to create bill attribute value
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiBillAttributeValueCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiAttribute')->apiBillAttributeValueCreate($request, $response, $data);
}
/**
* Api method to create bill attribute l11n
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiBillAttributeValueL11nCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
$this->app->moduleManager->get('Billing', 'ApiAttribute')->apiBillAttributeValueL11nCreate($request, $response, $data);
}
/**
* Api method to find subscriptions
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiSubscriptionFind(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
}
/**
* Api method to create item payment type
*
@ -436,8 +95,11 @@ final class ApiController extends Controller
*/
private function createPaymentTermFromRequest(RequestAbstract $request) : BaseStringL11nType
{
$paymentTerm = new BaseStringL11nType($request->getDataString('name') ?? '');
$paymentTerm->setL11n($request->getDataString('title') ?? '', $request->getDataString('language') ?? ISO639x1Enum::_EN);
$paymentTerm = new BaseStringL11nType($request->getDataString('name') ?? '');
$paymentTerm->setL11n(
$request->getDataString('title') ?? '',
ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? ISO639x1Enum::_EN
);
return $paymentTerm;
}
@ -501,12 +163,10 @@ final class ApiController extends Controller
*/
private function createPaymentTermL11nFromRequest(RequestAbstract $request) : BaseStringL11n
{
$paymentL11n = new BaseStringL11n();
$paymentL11n->ref = $request->getDataInt('type') ?? 0;
$paymentL11n->setLanguage(
$request->getDataString('language') ?? $request->header->l11n->language
);
$paymentL11n->content = $request->getDataString('title') ?? '';
$paymentL11n = new BaseStringL11n();
$paymentL11n->ref = $request->getDataInt('type') ?? 0;
$paymentL11n->language = ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? $request->header->l11n->language;
$paymentL11n->content = $request->getDataString('title') ?? '';
return $paymentL11n;
}
@ -570,8 +230,11 @@ final class ApiController extends Controller
*/
private function createShippingTermFromRequest(RequestAbstract $request) : BaseStringL11nType
{
$shippingTerm = new BaseStringL11nType($request->getDataString('name') ?? '');
$shippingTerm->setL11n($request->getDataString('title') ?? '', $request->getDataString('language') ?? ISO639x1Enum::_EN);
$shippingTerm = new BaseStringL11nType($request->getDataString('name') ?? '');
$shippingTerm->setL11n(
$request->getDataString('title') ?? '',
ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? ISO639x1Enum::_EN
);
return $shippingTerm;
}
@ -635,12 +298,10 @@ final class ApiController extends Controller
*/
private function createShippingTermL11nFromRequest(RequestAbstract $request) : BaseStringL11n
{
$shippingL11n = new BaseStringL11n();
$shippingL11n->ref = $request->getDataInt('type') ?? 0;
$shippingL11n->setLanguage(
$request->getDataString('language') ?? $request->header->l11n->language
);
$shippingL11n->content = $request->getDataString('title') ?? '';
$shippingL11n = new BaseStringL11n();
$shippingL11n->ref = $request->getDataInt('type') ?? 0;
$shippingL11n->language = ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? $request->header->l11n->language;
$shippingL11n->content = $request->getDataString('title') ?? '';
return $shippingL11n;
}

View File

@ -16,15 +16,20 @@ declare(strict_types=1);
namespace Modules\Billing\Controller;
use Modules\Attribute\Models\NullAttributeValue;
use Modules\Billing\Models\Price\NullPrice;
use Modules\Billing\Models\Price\Price;
use Modules\Billing\Models\Price\PriceMapper;
use Modules\Billing\Models\Price\PriceType;
use Modules\Billing\Models\Tax\TaxCombinationMapper;
use Modules\ClientManagement\Models\Client;
use Modules\ClientManagement\Models\ClientMapper;
use Modules\ClientManagement\Models\NullClient;
use Modules\Finance\Models\TaxCodeMapper;
use Modules\ItemManagement\Models\Item;
use Modules\ItemManagement\Models\ItemMapper;
use Modules\ItemManagement\Models\NullItem;
use Modules\SupplierManagement\Models\NullSupplier;
use Modules\SupplierManagement\Models\Supplier;
use Modules\SupplierManagement\Models\SupplierMapper;
use phpOMS\Localization\ISO4217CharEnum;
use phpOMS\Message\Http\RequestStatusCode;
@ -43,6 +48,177 @@ use phpOMS\System\MimeType;
*/
final class ApiPriceController extends Controller
{
public function findBestPrice(RequestAbstract $request, ?Item $item = null, ?Client $client = null, ?Supplier $supplier = null)
{
// Get item
if ($item === null && $request->hasData('price_item')) {
/** @var null|\Modules\ItemManagement\Models\Item $item */
$item = ItemMapper::get()
->with('attributes')
->with('attributes/type')
->with('attributes/value')
->where('id', (int) $request->getData('price_item'))
->where('attributes/type/name', ['segment', 'section', 'sales_group', 'product_group', 'product_type'], 'IN')
->execute();
}
// Get client
if ($client === null && $request->hasData('client')) {
/** @var \Modules\ClientManagement\Models\Client $client */
$client = ClientMapper::get()
->with('attributes')
->with('attributes/type')
->with('attributes/value')
->where('id', (int) $request->getData('client'))
->where('attributes/type/name', ['segment', 'section', 'client_group', 'client_type'], 'IN')
->execute();
}
$quantity = new FloatInt($request->getDataString('price_quantity') ?? 10000);
// Get all relevant prices
$queryMapper = PriceMapper::getAll();
if ($request->hasData('price_name')) {
$queryMapper->where('name', $request->getData('name'));
}
$queryMapper->where('promocode', \array_unique([$request->getData('promocode'), null]), 'IN');
$queryMapper->where('item', \array_unique([$request->getDataInt('item'), $item?->id, null]), 'IN');
$queryMapper->where('itemsalesgroup', \array_unique([$request->getDataInt('sales_group'), $item?->getAttribute('sales_group')->value->getValue(), null]), 'IN');
$queryMapper->where('itemproductgroup', \array_unique([$request->getDataInt('product_group'), $item?->getAttribute('product_group')->value->getValue(), null]), 'IN');
$queryMapper->where('itemsegment', \array_unique([$request->getDataInt('item_segment'), $item?->getAttribute('segment')->value->getValue(), null]), 'IN');
$queryMapper->where('itemsection', \array_unique([$request->getDataInt('item_section'), $item?->getAttribute('section')->value->getValue(), null]), 'IN');
$queryMapper->where('itemtype', \array_unique([$request->getDataInt('product_type'), $item?->getAttribute('product_type')->value->getValue(), null]), 'IN');
$queryMapper->where('client', \array_unique([$request->getDataInt('client'), $client?->id, null]), 'IN');
$queryMapper->where('clientgroup', \array_unique([$request->getDataInt('client_group'), $client?->getAttribute('client_group')->value->getValue(), null]), 'IN');
$queryMapper->where('clientsegment', \array_unique([$request->getDataInt('client_segment'), $client?->getAttribute('segment')->value->getValue(), null]), 'IN');
$queryMapper->where('clientsection', \array_unique([$request->getDataInt('client_section'), $client?->getAttribute('section')->value->getValue(), null]), 'IN');
$queryMapper->where('clienttype', \array_unique([$request->getDataInt('client_type'), $client?->getAttribute('client_type')->value->getValue(), null]), 'IN');
$queryMapper->where('clientcountry', \array_unique([$request->getData('client_region'), $client?->mainAddress->country, null]), 'IN');
$queryMapper->where('supplier', \array_unique([$request->getDataInt('supplier'), $supplier?->id, null]), 'IN');
$queryMapper->where('unit', \array_unique([$request->getDataInt('price_unit'), null]), 'IN');
$queryMapper->where('type', $request->getDataInt('price_type') ?? PriceType::SALES);
$queryMapper->where('currency', \array_unique([$request->getDataString('currency'), null]), 'IN');
// @todo implement start and end
/*
@todo implement quantity
if ($request->hasData('price_quantity')) {
$whereQuery = new Where();
$whereQuery->where('quantity', (int) $request->getData('price_quantity'), '<=')
->where('quantity', null, '=', 'OR')
$queryMapper->where('quantity', $whereQuery);
}
*/
/** @var \Modules\Billing\Models\Price\Price[] $prices */
$prices = $queryMapper->execute();
// Find base price (@todo probably not a good solution)
$basePrice = null;
foreach ($prices as $price) {
if ($price->priceNew > 0
&& $price->item->id !== 0
&& $price->itemsalesgroup->id === 0
&& $price->itemproductgroup->id === 0
&& $price->itemsegment->id === 0
&& $price->itemsection->id === 0
&& $price->itemtype->id === 0
&& $price->client->id === 0
&& $price->clientgroup->id === 0
&& $price->clientsegment->id === 0
&& $price->clientsection->id === 0
&& $price->clienttype->id === 0
&& $price->promocode === ''
&& $price->priceNew->value < ($basePrice?->priceNew->value ?? \PHP_INT_MAX)
) {
$basePrice = $price;
}
}
$basePrice ??= new NullPrice();
// @todo implement prices which cannot be improved even if there are better prices available (i.e. some customer groups may not get better prices, Dentagen Beispiel)
// alternatively set prices as 'improvable' => which whitelists a price as can be improved or 'alwaysimproces' which always overwrites other prices
// Find best price
$bestPrice = $basePrice;
$bestPriceValue = \PHP_INT_MAX;
$discounts = [];
foreach ($prices as $price) {
if ($price->isAdditive && $price->priceNew->value === 0) {
$discounts[] = $price;
}
$newPrice = $bestPrice->price->value ?? $basePrice->price->value;
if ($price->priceNew->value > 0 && $price->priceNew->value < $newPrice) {
$newPrice = $price->priceNew->value;
}
if ($price->priceNew->value > 0 && $price->priceNew->value < $newPrice) {
$newPrice = $price->priceNew->value;
}
// Calculate the price EFFECT (this is the theoretical unit price)
// 1. subtract discount value
// 2. subtract discount percentage
// 3. subtract bonus effect
$newPrice -= $price->discount->value;
$newPrice = (int) ($newPrice - $price->bonus->value / 10000 * $price->priceNew->value / $quantity->value);
$newPrice = (int) ((1000000 - $price->discountPercentage->value) / 1000000 * $newPrice);
// @todo If a customer receives 1+1 but purchases 2, then he gets 2+2 (if multiply === true) which is better than 1+1 with multiply false.
// Same goes for amount discounts?
if ($newPrice < $bestPriceValue) {
$bestPriceValue = $newPrice;
$bestPrice = $price;
}
}
if ($bestPrice->price->value === 0) {
$discounts[] = clone $bestPrice;
$bestPrice = $basePrice;
}
// Actual price calculation
$bestActualPriceValue = $bestPrice?->price->value ?? \PHP_INT_MAX;
$discountAmount = $bestPrice->discount->value;
$discountPercentage = $bestPrice->discountPercentage->value;
$bonus = $bestPrice->bonus->value;
foreach ($discounts as $discount) {
$bestActualPriceValue -= $discount->discount->value;
$discountAmount += $discount->discount->value;
$discountPercentage += $discount->discountPercentage->value;
$bonus += $discount->bonus->value;
}
$bestActualPriceValue -= $discountAmount;
$bestActualPriceValue = (int) \round((1000000 - $discountPercentage) / 1000000 * $bestActualPriceValue, 0);
return [
'basePrice' => $basePrice->price,
'bestPrice' => $bestPrice->price,
'bestActualPrice' => new FloatInt($bestActualPriceValue),
'discounts' => $discounts,
'discountPercent' => new FloatInt($discountPercentage),
'discountAmount' => new FloatInt($discountAmount),
'bonus' => new FloatInt($bonus),
];
}
/**
* Api method to find items
*
@ -74,13 +250,6 @@ final class ApiPriceController extends Controller
// Get account
/** @var null|\Modules\ClientManagement\Models\Client|\Modules\SupplierManagement\Models\Supplier $account */
$account = null;
/** @var null|\Modules\ClientManagement\Models\Client $client */
$client = null;
/** @var null|\Modules\SupplierManagement\Models\Supplier $supplier */
$supplier = null;
if ($request->hasData('client')) {
/** @var \Modules\ClientManagement\Models\Client $client */
$client = ClientMapper::get()
@ -105,6 +274,8 @@ final class ApiPriceController extends Controller
$account = $supplier;
}
$quantity = new FloatInt($request->getDataString('price_quantity') ?? 10000);
// Get all relevant prices
$queryMapper = PriceMapper::getAll();
@ -126,7 +297,7 @@ final class ApiPriceController extends Controller
$queryMapper->where('clientsegment', \array_unique([$request->getData('client_segment', 'int'), $client?->getAttribute('segment')->id, null]), 'IN');
$queryMapper->where('clientsection', \array_unique([$request->getData('client_section', 'int'), $client?->getAttribute('section')->id, null]), 'IN');
$queryMapper->where('clienttype', \array_unique([$request->getData('client_type', 'int'), $client?->getAttribute('client_type')->id, null]), 'IN');
$queryMapper->where('clientcountry', \array_unique([$request->getData('client_region'), $client?->mainAddress->getCountry(), null]), 'IN');
$queryMapper->where('clientcountry', \array_unique([$request->getData('client_region'), $client?->mainAddress->country, null]), 'IN');
$queryMapper->where('supplier', \array_unique([$request->getData('supplier', 'int'), null]), 'IN');
$queryMapper->where('unit', \array_unique([$request->getData('price_unit', 'int'), null]), 'IN');
@ -152,7 +323,7 @@ final class ApiPriceController extends Controller
// Find base price (@todo probably not a good solution)
$bestBasePrice = null;
foreach ($prices as $price) {
if ($price->price->value !== 0 && $price->priceNew === 0
if ($price->priceNew->value !== 0 && $price->priceNew === 0
&& $price->item->id !== 0
&& $price->itemsalesgroup->id === 0
&& $price->itemproductgroup->id === 0
@ -165,7 +336,7 @@ final class ApiPriceController extends Controller
&& $price->clientsection->id === 0
&& $price->clienttype->id === 0
&& $price->promocode === ''
&& $price->price->value < ($bestBasePrice?->price->value ?? \PHP_INT_MAX)
&& $price->priceNew->value < ($bestBasePrice?->price->value ?? \PHP_INT_MAX)
) {
$bestBasePrice = $price;
}
@ -180,20 +351,21 @@ final class ApiPriceController extends Controller
foreach ($prices as $price) {
$newPrice = $bestBasePrice?->price->value ?? \PHP_INT_MAX;
if ($price->price->value < $newPrice) {
$newPrice = $price->price->value;
if ($price->priceNew->value < $newPrice) {
$newPrice = $price->priceNew->value;
}
if ($price->priceNew < $newPrice) {
$newPrice = $price->priceNew;
}
// Calculate the price EFFECT (this is the theoretical unit price)
// 1. subtract discount value
// 2. subtract discount percentage
// 3. subtract bonus effect
$newPrice -= $price->discount;
$newPrice = (int) ((10000 / $price->discountPercentage) * $newPrice);
$newPrice = (int) (($price->quantity === 0 ? 10000 : $price->quantity) / (10000 + $price->bonus) * $newPrice);
$newPrice -= $price->discount->value;
$newPrice = (int) ((1000000 - $price->discountPercentage->value) / 1000000 * $newPrice);
$newPrice = (int) ($newPrice - $price->bonus->value / 10000 * $price->priceNew->value / $quantity->value);
// @todo the calculation above regarding discount and bonus don't consider the purchased quantity.
// If a customer receives 1+1 but purchases 2, then he gets 2+2 (if multiply === true) which is better than 1+1 with multiply false.
// @todo If a customer receives 1+1 but purchases 2, then he gets 2+2 (if multiply === true) which is better than 1+1 with multiply false.
// Same goes for amount discounts?
if ($newPrice < $bestPriceValue) {
$bestPriceValue = $newPrice;
@ -201,6 +373,12 @@ final class ApiPriceController extends Controller
}
}
// Actual price calculation
$bestActualPrice = $bestBasePrice?->price->value ?? \PHP_INT_MAX;
$bestActualPrice -= $bestPrice->discount->value;
// @todo now perform subtractive improvements (e.g. promocodes are often subtractive)
// Get tax definition
/** @var \Modules\Billing\Models\Tax\TaxCombination $tax */
$tax = ($request->getDataInt('price_type') ?? PriceType::SALES) === PriceType::SALES
@ -213,10 +391,22 @@ final class ApiPriceController extends Controller
->where('supplierCode', $account->getAttribute('supplier_code')->value->id)
->execute();
$taxCode = TaxCodeMapper::get()
->where('abbr', $tax->taxCode)
->execute();
$result = [
'taxcode' => $taxCode->abbr,
'grossPercentage' => $taxCode->percentageInvoice,
'net' => $bestActualPrice,
'taxes' => $bestActualPrice * $taxCode->percentageInvoice / 1000000,
'gross' => $bestActualPrice + $bestActualPrice * $taxCode->percentageInvoice / 1000000,
];
$response->header->set('Content-Type', MimeType::M_JSON, true);
$response->set(
$request->uri->__toString(),
\array_values($prices)
$result
);
}
@ -262,12 +452,12 @@ final class ApiPriceController extends Controller
$price->name = $request->getDataString('name') ?? '';
$price->promocode = $request->getDataString('promocode') ?? '';
$price->item = new NullItem((int) $request->getData('item'));
$price->itemsegment = new NullAttributeValue((int) $request->getData('itemsegment'));
$price->itemsection = new NullAttributeValue((int) $request->getData('itemsection'));
$price->item = new NullItem((int) $request->getData('item'));
$price->itemsegment = new NullAttributeValue((int) $request->getData('itemsegment'));
$price->itemsection = new NullAttributeValue((int) $request->getData('itemsection'));
$price->itemsalesgroup = new NullAttributeValue((int) $request->getData('itemsalesgroup'));
$price->itemproductgroup = new NullAttributeValue((int) $request->getData('itemproductgroup'));
$price->itemtype = new NullAttributeValue((int) $request->getData('itemtype'));
$price->itemproductgroup = new NullAttributeValue((int) $request->getData('itemproductgroup'));
$price->itemtype = new NullAttributeValue((int) $request->getData('itemtype'));
$price->client = new NullClient((int) $request->getData('client'));
$price->clientsegment = new NullAttributeValue((int) $request->getData('clientsegment'));
@ -277,15 +467,15 @@ final class ApiPriceController extends Controller
$price->supplier = new NullSupplier((int) $request->getData('supplier'));
$price->unit = (int) $request->getData('unit');
$price->type = $request->getDataInt('type') ?? PriceType::SALES;
$price->quantity = (int) $request->getData('quantity');
$price->price = new FloatInt((int) $request->getData('price'));
$price->priceNew = (int) $request->getData('price_new');
$price->discount = (int) $request->getData('discount');
$price->discountPercentage = (int) $request->getData('discountPercentage');
$price->bonus = (int) $request->getData('bonus');
$price->type = PriceType::tryFromValue($request->getDataInt('type')) ?? PriceType::SALES;
$price->quantity = new FloatInt($request->getDataString('quantity') ?? 0);
$price->price = new FloatInt($request->getDataString('price') ?? 0);
$price->priceNew = new FloatInt($request->getDataString('price_new') ?? 0);
$price->discount = new FloatInt($request->getDataString('discount') ?? 0);
$price->discountPercentage = new FloatInt($request->getDataString('discountPercentage') ?? 0);
$price->bonus = new FloatInt($request->getDataString('bonus') ?? 0);
$price->multiply = $request->getDataBool('multiply') ?? false;
$price->currency = $request->getDataString('currency') ?? ISO4217CharEnum::_EUR;
$price->currency = ISO4217CharEnum::tryFromValue($request->getDataString('currency')) ?? ISO4217CharEnum::_EUR;
$price->start = $request->getDataDateTime('start');
$price->end = $request->getDataDateTime('end');
@ -299,7 +489,7 @@ final class ApiPriceController extends Controller
*
* @return array<string, bool>
*
* @todo consider to prevent name 'base'?
* @todo consider to prevent name 'default'?
* Might not be possible because it is used internally as well (see apiItemCreate in ItemManagement)
*
* @since 1.0.0
@ -356,18 +546,18 @@ final class ApiPriceController extends Controller
*/
public function updatePriceFromRequest(RequestAbstract $request, Price $new) : Price
{
$new->name = $new->name !== 'base'
$new->name = $new->name !== 'default'
? ($request->getDataString('name') ?? $new->name)
: $new->name;
$new->promocode = $request->getDataString('promocode') ?? $new->promocode;
$new->item = $request->hasData('item') ? new NullItem((int) $request->getData('item')) : $new->item;
$new->item = $request->hasData('item') ? new NullItem((int) $request->getData('item')) : $new->item;
$new->itemsalesgroup = $request->hasData('itemsalesgroup') ? new NullAttributeValue((int) $request->getData('itemsalesgroup')) : $new->itemsalesgroup;
$new->itemproductgroup = $request->hasData('itemproductgroup') ? new NullAttributeValue((int) $request->getData('itemproductgroup')) : $new->itemproductgroup;
$new->itemsegment = $request->hasData('itemsegment') ? new NullAttributeValue((int) $request->getData('itemsegment')) : $new->itemsegment;
$new->itemsection = $request->hasData('itemsection') ? new NullAttributeValue((int) $request->getData('itemsection')) : $new->itemsection;
$new->itemtype = $request->hasData('itemtype') ? new NullAttributeValue((int) $request->getData('itemtype')) : $new->itemtype;
$new->itemproductgroup = $request->hasData('itemproductgroup') ? new NullAttributeValue((int) $request->getData('itemproductgroup')) : $new->itemproductgroup;
$new->itemsegment = $request->hasData('itemsegment') ? new NullAttributeValue((int) $request->getData('itemsegment')) : $new->itemsegment;
$new->itemsection = $request->hasData('itemsection') ? new NullAttributeValue((int) $request->getData('itemsection')) : $new->itemsection;
$new->itemtype = $request->hasData('itemtype') ? new NullAttributeValue((int) $request->getData('itemtype')) : $new->itemtype;
$new->client = $request->hasData('client') ? new NullClient((int) $request->getData('client')) : $new->client;
$new->clientgroup = $request->hasData('clientgroup') ? new NullAttributeValue((int) $request->getData('clientgroup')) : $new->clientgroup;
@ -377,7 +567,7 @@ final class ApiPriceController extends Controller
$new->supplier = $request->hasData('supplier') ? new NullSupplier((int) $request->getData('supplier')) : $new->supplier;
$new->unit = $request->getDataInt('unit') ?? $new->unit;
$new->type = $request->getDataInt('type') ?? $new->type;
$new->type = PriceType::tryFromValue($request->getDataInt('type')) ?? $new->type;
$new->quantity = $request->getDataInt('quantity') ?? $new->quantity;
$new->price = $request->hasData('price') ? new FloatInt((int) $request->getData('price')) : $new->price;
$new->priceNew = $request->getDataInt('price_new') ?? $new->priceNew;
@ -400,7 +590,7 @@ final class ApiPriceController extends Controller
* @return array<string, bool>
*
* @todo implement
* @todo consider to block 'base' name
* @todo consider to block 'default' name
*
* @since 1.0.0
*/
@ -439,7 +629,7 @@ final class ApiPriceController extends Controller
/** @var \Modules\Billing\Models\Price\Price $price */
$price = PriceMapper::get()->where('id', (int) $request->getData('id'))->execute();
if ($price->name === 'base') {
if ($price->name === 'default') {
// default price cannot be deleted
$this->createInvalidDeleteResponse($request, $response, []);

View File

@ -27,7 +27,6 @@ use phpOMS\Message\ResponseAbstract;
use phpOMS\System\OperatingSystem;
use phpOMS\System\SystemType;
use phpOMS\System\SystemUtils;
use phpOMS\Uri\HttpUri;
/**
* Billing class.
@ -73,7 +72,7 @@ final class ApiPurchaseController extends Controller
$files = $request->files;
foreach ($files as $file) {
// Create default bill
$billRequest = new HttpRequest(new HttpUri(''));
$billRequest = new HttpRequest();
$billRequest->header->account = $request->header->account;
$billRequest->header->l11n = $request->header->l11n;
$billRequest->setData('supplier', 0);
@ -83,7 +82,7 @@ final class ApiPurchaseController extends Controller
$billResponse = new HttpResponse();
$billResponse->header->l11n = $response->header->l11n;
$this->app->moduleManager->get('Billing', 'Api')->apiBillCreate($billRequest, $billResponse, $data);
$this->app->moduleManager->get('Billing', 'ApiBill')->apiBillCreate($billRequest, $billResponse, $data);
$billId = $billResponse->getDataArray('')['response']->id;
@ -99,7 +98,7 @@ final class ApiPurchaseController extends Controller
$mediaRequest->setData('bill', $billId);
$mediaRequest->setData('type', $originalType);
$mediaRequest->setData('parse_content', true, true);
$this->app->moduleManager->get('Billing', 'Api')->apiMediaAddToBill($mediaRequest, $mediaResponse, $data);
$this->app->moduleManager->get('Billing', 'ApiBill')->apiMediaAddToBill($mediaRequest, $mediaResponse, $data);
/** @var \Modules\Media\Models\Media[] $uploaded */
$uploaded = $mediaResponse->getDataArray('')['response']['upload'];
@ -116,12 +115,12 @@ final class ApiPurchaseController extends Controller
// Create internal document
$billResponse = new HttpResponse();
$billRequest = new HttpRequest(new HttpUri(''));
$billRequest = new HttpRequest();
$billRequest->header->account = $request->header->account;
$billRequest->setData('bill', $billId);
$this->app->moduleManager->get('Billing', 'Api')->apiBillPdfArchiveCreate($billRequest, $billResponse);
$this->app->moduleManager->get('Billing', 'ApiBill')->apiBillPdfArchiveCreate($billRequest, $billResponse);
// Offload bill parsing to cli
$cliPath = \realpath(__DIR__ . '/../../../cli.php');

View File

@ -20,11 +20,11 @@ use Modules\Billing\Models\Tax\TaxCombination;
use Modules\Billing\Models\Tax\TaxCombinationMapper;
use Modules\ClientManagement\Models\Attribute\ClientAttributeTypeMapper;
use Modules\ClientManagement\Models\Client;
use Modules\Finance\Models\TaxCode;
use Modules\Finance\Models\TaxCodeMapper;
use Modules\ItemManagement\Models\Item;
use Modules\Organization\Models\UnitMapper;
use phpOMS\Localization\ISO3166CharEnum;
use Modules\SupplierManagement\Models\Attribute\SupplierAttributeTypeMapper;
use Modules\SupplierManagement\Models\Supplier;
use phpOMS\Localization\ISO3166TwoEnum;
use phpOMS\Message\Http\RequestStatusCode;
use phpOMS\Message\RequestAbstract;
use phpOMS\Message\ResponseAbstract;
@ -48,28 +48,35 @@ final class ApiTaxController extends Controller
* @param Item $item Item to get tax code from
* @param string $defaultCountry default country to use if no valid tax code could be found and if the unit country code shouldn't be used
*
* @return TaxCode
* @return TaxCombination
*
* @since 1.0.0
*/
public function getTaxCodeFromClientItem(Client $client, Item $item, string $defaultCountry = '') : TaxCode
public function getTaxForPerson(?Client $client = null, ?Supplier $supplier = null, Item $item, string $defaultCountry = '') : TaxCombination
{
// @todo define default sales tax code if none available?!
// @todo consider to actually use a ownsOne reference instead of only a string, this way the next line with the TaxCodeMapper can be removed
$itemCode = 0;
$accountCode = 0;
$combinationType = 'clientCode';
if ($client !== null) {
$itemCode = $item->getAttribute('sales_tax_code')->value->id;
$accountCode = $client->getAttribute('sales_tax_code')->value->id;
} else {
$itemCode = $item->getAttribute('purchase_tax_code')->value->id;
$accountCode = $supplier->getAttribute('purchase_tax_code')->value->id;
$combinationType = 'supplierCode';
}
/** @var \Modules\Billing\Models\Tax\TaxCombination $taxCombination */
$taxCombination = TaxCombinationMapper::get()
->where('itemCode', $item->getAttribute('sales_tax_code')->value->id)
->where('clientCode', $client->getAttribute('sales_tax_code')->value->id)
->with('taxCode')
->where('itemCode', $itemCode)
->where($combinationType, $accountCode)
->execute();
/** @var \Modules\Finance\Models\TaxCode $taxCode */
$taxCode = TaxCodeMapper::get()
->where('abbr', $taxCombination->taxCode)
->execute();
if ($taxCode->id !== 0) {
return $taxCode;
if ($taxCombination->taxCode->id !== 0) {
return $taxCombination;
}
/** @var \Modules\Organization\Models\Unit $unit */
@ -78,28 +85,23 @@ final class ApiTaxController extends Controller
->where('id', $this->app->unitId)
->execute();
// Create dummy client
$client = new Client();
$client->mainAddress = $unit->mainAddress;
// Create dummy
$account = $client !== null ? new Client() : new Supplier();
$account->mainAddress = $unit->mainAddress;
if (!empty($defaultCountry)) {
$client->mainAddress->setCountry($defaultCountry);
$account->mainAddress->setCountry($defaultCountry);
}
$taxCodeAttribute = $this->getClientTaxCode($client, $unit->mainAddress);
$taxCodeAttribute = $client !== null
? $this->getClientTaxCode($account, $unit->mainAddress)
: $this->getSupplierTaxCode($account, $unit->mainAddress);
/** @var \Modules\Billing\Models\Tax\TaxCombination $taxCombination */
$taxCombination = TaxCombinationMapper::get()
->where('itemCode', $item->getAttribute('sales_tax_code')->value->id)
->where('clientCode', $taxCodeAttribute->id)
return TaxCombinationMapper::get()
->with('taxCode')
->where('itemCode', $itemCode)
->where($combinationType, $taxCodeAttribute->id)
->execute();
/** @var \Modules\Finance\Models\TaxCode $taxCode */
$taxCode = TaxCodeMapper::get()
->where('abbr', $taxCombination->taxCode)
->execute();
return $taxCode;
}
/**
@ -138,10 +140,10 @@ final class ApiTaxController extends Controller
*/
private function createTaxCombinationFromRequest(RequestAbstract $request) : TaxCombination
{
$tax = new TaxCombination();
$tax->taxType = $request->getDataInt('tax_type') ?? 1;
$tax->taxCode = (string) $request->getData('tax_code');
$tax->itemCode = new NullAttributeValue((int) $request->getData('item_code'));
$tax = new TaxCombination();
$tax->taxType = $request->getDataInt('tax_type') ?? 1;
$tax->taxCode->abbr = (string) $request->getData('tax_code');
$tax->itemCode = new NullAttributeValue((int) $request->getData('item_code'));
if ($tax->taxType === 1) {
$tax->clientCode = new NullAttributeValue((int) $request->getData('account_code'));
@ -196,24 +198,72 @@ final class ApiTaxController extends Controller
$taxCode = new NullAttributeValue();
// @todo need to consider own tax id as well
if ($taxOfficeAddress->getCountry() === $client->mainAddress->getCountry()) {
$taxCode = $codes->getDefaultByValue($client->mainAddress->getCountry());
} elseif (\in_array($taxOfficeAddress->getCountry(), ISO3166CharEnum::getRegion('eu'))
&& \in_array($client->mainAddress->getCountry(), ISO3166CharEnum::getRegion('eu'))
// @todo consider delivery & invoice location (Reihengeschaeft)
if ($taxOfficeAddress->country === $client->mainAddress->country) {
// Same country as we (= local tax code)
return $codes->getDefaultByValue($client->mainAddress->country);
} elseif (\in_array($taxOfficeAddress->country, ISO3166TwoEnum::getRegion('eu'))
&& \in_array($client->mainAddress->country, ISO3166TwoEnum::getRegion('eu'))
) {
if (!empty($client->getAttribute('vat_id')->value->getValue())) {
// Is EU company
$taxCode = $codes->getDefaultByValue('EU');
// Is EU company and we are EU company
return $codes->getDefaultByValue('EU');
} else {
// Is EU private customer
$taxCode = $codes->getDefaultByValue($client->mainAddress->getCountry());
// Is EU private customer and we are EU company
return $codes->getDefaultByValue($client->mainAddress->country);
}
} elseif (\in_array($taxOfficeAddress->getCountry(), ISO3166CharEnum::getRegion('eu'))) {
} elseif (\in_array($taxOfficeAddress->country, ISO3166TwoEnum::getRegion('eu'))) {
// None EU company but we are EU company
$taxCode = $codes->getDefaultByValue('INT');
return $codes->getDefaultByValue('INT');
} else {
// None EU company and we are also none EU company
$taxCode = $codes->getDefaultByValue('INT');
return $codes->getDefaultByValue('INT');
}
return $taxCode;
}
/**
* Get the client's tax code based on their country and tax office address
*
* @param Supplier $client The client to get the tax code for
* @param Address $taxOfficeAddress The tax office address used to determine the tax code
*
* @return AttributeValue The client's tax code
*
* @since 1.0.0
*/
public function getSupplierTaxCode(Supplier $client, Address $taxOfficeAddress) : AttributeValue
{
/** @var \Modules\Attribute\Models\AttributeType $codes */
$codes = SupplierAttributeTypeMapper::get()
->with('defaults')
->where('name', 'purchase_tax_code')
->execute();
$taxCode = new NullAttributeValue();
// @todo need to consider own tax id as well
// @todo consider delivery & invoice location (Reihengeschaeft)
if ($taxOfficeAddress->country === $client->mainAddress->country) {
// Same country as we (= local tax code)
return $codes->getDefaultByValue($client->mainAddress->country);
} elseif (\in_array($taxOfficeAddress->country, ISO3166TwoEnum::getRegion('eu'))
&& \in_array($client->mainAddress->country, ISO3166TwoEnum::getRegion('eu'))
) {
if (!empty($client->getAttribute('vat_id')->value->getValue())) {
// Is EU company and we are EU company
return $codes->getDefaultByValue('EU');
} else {
// Is EU private customer and we are EU company
return $codes->getDefaultByValue($client->mainAddress->country);
}
} elseif (\in_array($taxOfficeAddress->country, ISO3166TwoEnum::getRegion('eu'))) {
// None EU company but we are EU company
return $codes->getDefaultByValue('INT');
} else {
// None EU company and we are also none EU company
return $codes->getDefaultByValue('INT');
}
return $taxCode;

View File

@ -113,6 +113,7 @@ final class BackendController extends Controller
$bill = SalesBillMapper::get()
->with('client')
->with('elements')
->with('elements/container')
->with('files')
->with('files/types')
->with('notes')
@ -144,14 +145,12 @@ final class BackendController extends Controller
->with('createdBy')
->where('module', 'Billing')
->where('type', StringUtils::intHash(BillElementMapper::class))
->where('ref', \array_keys($bill->getElements()), 'IN')
->where('ref', \array_keys($bill->elements), 'IN')
->execute();
$logs = \array_merge($logs, $logsElements);
}
$logs = \array_merge($logs, $logsElements);
$view->data['logs'] = $logs;
$view->data['media-upload'] = new \Modules\Media\Theme\Backend\Components\Upload\BaseView($this->app->l11nManager, $request, $response);
@ -298,7 +297,9 @@ final class BackendController extends Controller
$view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1005105001, $request, $response);
$bill = PurchaseBillMapper::get()
->with('supplier')
->with('elements')
->with('elements/container')
->with('files')
->with('files/types')
->with('notes')
@ -338,7 +339,7 @@ final class BackendController extends Controller
->with('createdBy')
->where('module', 'Billing')
->where('type', StringUtils::intHash(BillElementMapper::class))
->where('ref', \array_keys($bill->getElements()), 'IN')
->where('ref', \array_keys($bill->elements), 'IN')
->execute();
$logs = \array_merge($logs, $logsElements);

View File

@ -63,7 +63,7 @@ final class CliController extends Controller
/** @var \Modules\Billing\Models\Bill $bill */
$bill = BillMapper::get()
->with('media')
->with('files')
->with('media/types')
->with('media/content')
->where('id', (int) $request->getData('i'))
@ -97,13 +97,13 @@ final class CliController extends Controller
$supplierId = $this->matchSupplier($content, $suppliers);
$bill->supplier = new NullSupplier($supplierId);
$supplier = $suppliers[$supplierId] ?? new NullSupplier();
$supplier = $suppliers[$supplierId] ?? new NullSupplier();
$bill->billTo = $supplier->account->name1;
$bill->billAddress = $supplier->mainAddress->address;
$bill->billCity = $supplier->mainAddress->city;
$bill->billZip = $supplier->mainAddress->postal;
$bill->billCountry = $supplier->mainAddress->getCountry();
$bill->billCountry = $supplier->mainAddress->country;
/* Type */
$type = $this->findSupplierInvoiceType($content, $identifiers['type'], $language);
@ -150,6 +150,8 @@ final class CliController extends Controller
$view->setTemplate('/Modules/Billing/Theme/Cli/bill-parsed');
$view->data['bill'] = $bill;
// @todo change tax code during/after bill parsing
return $view;
}

View File

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

View File

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

View File

@ -37,15 +37,15 @@ final class BillAttributeValueMapper extends DataMapperFactory
* @since 1.0.0
*/
public const COLUMNS = [
'billing_attr_value_id' => ['name' => 'billing_attr_value_id', 'type' => 'int', 'internal' => 'id'],
'billing_attr_value_default' => ['name' => 'billing_attr_value_default', 'type' => 'bool', 'internal' => 'isDefault'],
'billing_attr_value_valueStr' => ['name' => 'billing_attr_value_valueStr', 'type' => 'string', 'internal' => 'valueStr'],
'billing_attr_value_valueInt' => ['name' => 'billing_attr_value_valueInt', 'type' => 'int', 'internal' => 'valueInt'],
'billing_attr_value_valueDec' => ['name' => 'billing_attr_value_valueDec', 'type' => 'float', 'internal' => 'valueDec'],
'billing_attr_value_valueDat' => ['name' => 'billing_attr_value_valueDat', 'type' => 'DateTime', 'internal' => 'valueDat'],
'billing_attr_value_unit' => ['name' => 'billing_attr_value_unit', 'type' => 'string', 'internal' => 'unit'],
'billing_attr_value_deptype' => ['name' => 'billing_attr_value_deptype', 'type' => 'int', 'internal' => 'dependingAttributeType'],
'billing_attr_value_depvalue' => ['name' => 'billing_attr_value_depvalue', 'type' => 'int', 'internal' => 'dependingAttributeValue'],
'billing_attr_value_id' => ['name' => 'billing_attr_value_id', 'type' => 'int', 'internal' => 'id'],
'billing_attr_value_default' => ['name' => 'billing_attr_value_default', 'type' => 'bool', 'internal' => 'isDefault'],
'billing_attr_value_valueStr' => ['name' => 'billing_attr_value_valueStr', 'type' => 'string', 'internal' => 'valueStr'],
'billing_attr_value_valueInt' => ['name' => 'billing_attr_value_valueInt', 'type' => 'int', 'internal' => 'valueInt'],
'billing_attr_value_valueDec' => ['name' => 'billing_attr_value_valueDec', 'type' => 'float', 'internal' => 'valueDec'],
'billing_attr_value_valueDat' => ['name' => 'billing_attr_value_valueDat', 'type' => 'DateTime', 'internal' => 'valueDat'],
'billing_attr_value_unit' => ['name' => 'billing_attr_value_unit', 'type' => 'string', 'internal' => 'unit'],
'billing_attr_value_deptype' => ['name' => 'billing_attr_value_deptype', 'type' => 'int', 'internal' => 'dependingAttributeType'],
'billing_attr_value_depvalue' => ['name' => 'billing_attr_value_depvalue', 'type' => 'int', 'internal' => 'dependingAttributeValue'],
];
/**

View File

@ -17,7 +17,6 @@ namespace Modules\Billing\Models;
use Modules\Admin\Models\Account;
use Modules\Admin\Models\NullAccount;
use Modules\ClientManagement\Models\Client;
use Modules\Media\Models\Collection;
use Modules\SupplierManagement\Models\Supplier;
use phpOMS\Localization\ISO4217CharEnum;
use phpOMS\Localization\ISO639x1Enum;
@ -74,7 +73,9 @@ class Bill implements \JsonSerializable
*/
public BillType $type;
public ?Collection $template = null;
public bool $isTemplate = false;
public bool $isArchived = false;
/**
* Bill status.
@ -313,20 +314,14 @@ class Bill implements \JsonSerializable
public FloatInt $grossDiscount;
/**
* Insurance fees in net.
* Tax amount
*
* @var FloatInt
* @since 1.0.0
*/
public FloatInt $insurance;
public FloatInt $taxP;
/**
* Freight in net.
*
* @var FloatInt
* @since 1.0.0
*/
public FloatInt $freight;
public ?int $accTaxCode = null;
/**
* Currency.
@ -379,6 +374,7 @@ class Bill implements \JsonSerializable
public int $terms = 0;
public ?int $paymentTerms = null;
public ?int $shippingTerms = null;
/**
@ -429,6 +425,16 @@ class Bill implements \JsonSerializable
*/
public int $reference = 0;
public ?int $accSegment = null;
public ?int $accSection = null;
public ?int $accGroup = null;
public ?int $accType = null;
public ?string $fiAccount = null;
/**
* Constructor.
*
@ -444,6 +450,7 @@ class Bill implements \JsonSerializable
$this->grossSales = new FloatInt(0);
$this->netDiscount = new FloatInt(0);
$this->grossDiscount = new FloatInt(0);
$this->taxP = new FloatInt(0);
$this->billDate = new \DateTime('now');
$this->createdAt = new \DateTimeImmutable();
@ -452,18 +459,6 @@ class Bill implements \JsonSerializable
$this->type = new NullBillType();
}
/**
* Get id.
*
* @return int Model id
*
* @since 1.0.0
*/
public function getId() : int
{
return $this->id;
}
/**
* Build the invoice number.
*
@ -494,7 +489,7 @@ class Bill implements \JsonSerializable
$this->type->id,
$this->unit,
$this->accountNumber,
$this->billCountry
$this->billCountry,
],
$this->type->numberFormat
);
@ -516,32 +511,6 @@ class Bill implements \JsonSerializable
return $this->number;
}
/**
* Get status
*
* @return int
*
* @since 1.0.0
*/
public function getStatus() : int
{
return $this->status;
}
/**
* Set status
*
* @param int $status Status
*
* @return void
*
* @since 1.0.0
*/
public function setStatus(int $status) : void
{
$this->status = $status;
}
/**
* Get paymentStatus
*
@ -568,96 +537,6 @@ class Bill implements \JsonSerializable
$this->paymentStatus = $paymentStatus;
}
/**
* Set currency.
*
* @param string $currency Currency
*
* @return void
*
* @since 1.0.0
*/
public function setCurrency(string $currency) : void
{
$this->currency = $currency;
}
/**
* Get currency.
*
* @return string
*
* @since 1.0.0
*/
public function getCurrency() : string
{
return $this->currency;
}
/**
* Get vouchers.
*
* @return array
*
* @since 1.0.0
*/
public function getVouchers() : array
{
return $this->vouchers;
}
/**
* Add voucher.
*
* @param string $voucher Voucher code
*
* @return void
*
* @since 1.0.0
*/
public function addVoucher(string $voucher) : void
{
$this->vouchers[] = $voucher;
}
/**
* Get tracking ids for shipment.
*
* @return array
*
* @since 1.0.0
*/
public function getTrackings() : array
{
return $this->trackings;
}
/**
* Add tracking id.
*
* @param string $tracking Tracking id
*
* @return void
*
* @since 1.0.0
*/
public function addTracking(string $tracking) : void
{
$this->trackings[] = $tracking;
}
/**
* Get Bill elements.
*
* @return BillElement[]
*
* @since 1.0.0
*/
public function getElements() : array
{
return $this->elements;
}
/**
* Add Bill element.
*
@ -671,16 +550,16 @@ class Bill implements \JsonSerializable
{
$this->elements[] = $element;
$this->netProfit->add($element->totalProfitNet->getInt());
$this->grossProfit->add($element->totalProfitGross->getInt());
$this->netCosts->add($element->totalPurchasePriceNet->getInt());
$this->grossCosts->add($element->totalPurchasePriceGross->getInt());
$this->netSales->add($element->totalSalesPriceNet->getInt());
$this->grossSales->add($element->totalSalesPriceGross->getInt());
$this->netDiscount->add($element->totalDiscountP->getInt());
$this->netProfit->value += $element->totalProfitNet->value;
$this->grossProfit->value += $element->totalProfitGross->value;
$this->netCosts->value += $element->totalPurchasePriceNet->value;
$this->grossCosts->value += $element->totalPurchasePriceGross->value;
$this->netSales->value += $element->totalSalesPriceNet->value;
$this->grossSales->value += $element->totalSalesPriceGross->value;
$this->netDiscount->value += $element->totalDiscountP->value;
// @todo Discount might be in quantities
$this->grossDiscount->add((int) ($element->taxR->getInt() * $element->totalDiscountP->getInt() / 10000));
$this->grossDiscount->value += (int) ($element->taxR->value * $element->totalDiscountP->value / 10000);
}
/**
@ -689,21 +568,21 @@ class Bill implements \JsonSerializable
public function toArray() : array
{
return [
'id' => $this->id,
'number' => $this->number,
'type' => $this->type,
'shipTo' => $this->shipTo,
'shipFAO' => $this->shipFAO,
'shipAddress' => $this->shipAddress,
'shipCity' => $this->shipCity,
'shipZip' => $this->shipZip,
'shipCountry' => $this->shipCountry,
'billTo' => $this->billTo,
'billFAO' => $this->billFAO,
'billAddress' => $this->billAddress,
'billCity' => $this->billCity,
'billZip' => $this->billZip,
'billCountry' => $this->billCountry,
'id' => $this->id,
'number' => $this->number,
'type' => $this->type,
'shipTo' => $this->shipTo,
'shipFAO' => $this->shipFAO,
'shipAddress' => $this->shipAddress,
'shipCity' => $this->shipCity,
'shipZip' => $this->shipZip,
'shipCountry' => $this->shipCountry,
'billTo' => $this->billTo,
'billFAO' => $this->billFAO,
'billAddress' => $this->billAddress,
'billCity' => $this->billCity,
'billZip' => $this->billZip,
'billCountry' => $this->billCountry,
];
}

View File

@ -14,7 +14,9 @@ declare(strict_types=1);
namespace Modules\Billing\Models;
use Modules\Billing\Models\Tax\TaxCombination;
use Modules\Finance\Models\TaxCode;
use Modules\ItemManagement\Models\Container;
use Modules\ItemManagement\Models\Item;
use Modules\ItemManagement\Models\NullItem;
use phpOMS\Stdlib\Base\FloatInt;
@ -42,18 +44,38 @@ class BillElement implements \JsonSerializable
public ?Item $item = null;
public ?Container $container = null;
public string $itemNumber = '';
public string $itemName = '';
public string $itemDescription = '';
public int $quantity = 0;
/**
* Line quantity
*
* Careful this also includes the bonus items defined in $discountQ!
*
* @var FloatInt
* @since 1.0.0
*/
public FloatInt $quantity;
public ?Subscription $subscription = null;
/**
* Single unit price
*
* Careful this is NOT corrected by bonus items defined in $discountQ
*
* @var FloatInt
* @since 1.0.0
*/
public FloatInt $singleSalesPriceNet;
public FloatInt $effectiveSingleSalesPriceNet;
public FloatInt $singleSalesPriceGross;
public FloatInt $totalSalesPriceNet;
@ -64,9 +86,9 @@ class BillElement implements \JsonSerializable
public FloatInt $totalDiscountP;
public ?FloatInt $singleDiscountR = null;
public FloatInt $singleDiscountR;
public ?FloatInt $discountQ = null;
public FloatInt $discountQ;
public FloatInt $singleListPriceNet;
@ -92,6 +114,22 @@ class BillElement implements \JsonSerializable
public FloatInt $totalProfitGross;
public ?int $itemSegment = null;
public ?int $itemSection = null;
public ?int $itemSalesGroup = null;
public ?int $itemProductGroup = null;
public ?int $itemType = null;
public string $fiAccount = '';
public ?string $costcenter = null;
public ?string $costobject = null;
/**
* Tax amount
*
@ -128,6 +166,9 @@ class BillElement implements \JsonSerializable
public Bill $bill;
// Distribution of lots/sn and from which stock location
public array $identifiers = [];
/**
* Constructor.
*
@ -137,6 +178,8 @@ class BillElement implements \JsonSerializable
{
$this->bill = new NullBill();
$this->quantity = new FloatInt();
$this->singleListPriceNet = new FloatInt();
$this->singleListPriceGross = new FloatInt();
@ -146,6 +189,8 @@ class BillElement implements \JsonSerializable
$this->singleSalesPriceNet = new FloatInt();
$this->singleSalesPriceGross = new FloatInt();
$this->effectiveSingleSalesPriceNet = new FloatInt();
$this->totalSalesPriceNet = new FloatInt();
$this->totalSalesPriceGross = new FloatInt();
@ -163,23 +208,13 @@ class BillElement implements \JsonSerializable
$this->singleDiscountP = new FloatInt();
$this->totalDiscountP = new FloatInt();
$this->singleDiscountR = new FloatInt();
$this->discountQ = new FloatInt();
$this->taxP = new FloatInt();
$this->taxR = new FloatInt();
}
/**
* Get id.
*
* @return int Model id
*
* @since 1.0.0
*/
public function getId() : int
{
return $this->id;
}
/**
* Set the element quantity.
*
@ -196,19 +231,30 @@ class BillElement implements \JsonSerializable
}
$this->quantity = $quantity;
// @todo recalculate all the prices!!!
$this->recalculatePrices();
}
/**
* Get quantity.
*
* @return int
*
* @since 1.0.0
*/
public function getQuantity() : int
public function recalculatePrices() : void
{
return $this->quantity;
$this->totalListPriceNet->value = (int) \round(($this->quantity->getNormalizedValue() - $this->discountQ->getNormalizedValue()) * $this->singleListPriceNet->value, 0);
$this->totalSalesPriceNet->value = (int) \round(($this->quantity->getNormalizedValue() - $this->discountQ->getNormalizedValue()) * $this->singleListPriceNet->value, 0);
$this->singleProfitNet->value = $this->singleSalesPriceNet->value - $this->singlePurchasePriceNet->value;
$this->totalProfitNet->value = $this->totalSalesPriceNet->value - $this->totalPurchasePriceNet->value;
$this->taxP->value = (int) \round($this->taxR->value / 1000000 * $this->totalSalesPriceNet->value, 0);
$this->singleListPriceGross->value = (int) \round($this->singleListPriceNet->value + $this->singleListPriceNet->value * $this->taxR->value / 10000, 0);
$this->totalListPriceGross->value = (int) \round($this->totalListPriceNet->value + $this->totalListPriceNet->value * $this->taxR->value / 10000, 0);
$this->singleSalesPriceGross->value = (int) \round($this->singleSalesPriceNet->value + $this->singleSalesPriceNet->value * $this->taxR->value / 10000, 0);
$this->totalSalesPriceGross->value = (int) \round($this->totalSalesPriceNet->value + $this->totalSalesPriceNet->value * $this->taxR->value / 10000, 0);
$this->singleProfitGross->value = $this->singleSalesPriceGross->value - $this->singlePurchasePriceGross->value;
$this->totalProfitGross->value = (int) \round(($this->quantity->getNormalizedValue() - $this->discountQ->getNormalizedValue()) * ($this->totalSalesPriceGross->value - $this->totalPurchasePriceGross->value), 0);
// important because the quantity includes $discountQ
$this->effectiveSingleSalesPriceNet->value = (int) \round($this->totalSalesPriceNet->value / ($this->quantity->value / 10000));
}
/**
@ -229,7 +275,7 @@ class BillElement implements \JsonSerializable
* Create element from item
*
* @param Item $item Item
* @param TaxCode $code Tax code used for gross amount calculation
* @param TaxCode $taxCode Tax code used for gross amount calculation
* @param int $quantity Quantity
* @param int $bill Bill
*
@ -237,41 +283,33 @@ class BillElement implements \JsonSerializable
*
* @since 1.0.0
*/
public static function fromItem(Item $item, TaxCode $code, int $quantity = 1, int $bill = 0) : self
public static function fromItem(
Item $item,
TaxCombination $taxCombination,
int $quantity = 10000,
int $bill = 0,
?Container $container = null
) : self
{
$element = new self();
$element->bill = new NullBill($bill);
$element->item = empty($item->id) ? null : $item;
$element->container = empty($container->id) ? null : $container;
$element->itemNumber = $item->number;
$element->itemName = $item->getL11n('name1')->content;
$element->itemDescription = $item->getL11n('description_short')->content;
$element->quantity = $quantity;
$element->quantity->value = $quantity;
// @todo Use pricing instead of the default sales price
// @todo discounts might be in quantities
$element->singleListPriceNet->setInt($item->salesPrice->getInt());
$element->totalListPriceNet->setInt($element->quantity * $item->salesPrice->getInt());
$element->singleSalesPriceNet->setInt($item->salesPrice->getInt());
$element->totalSalesPriceNet->setInt($element->quantity * $item->salesPrice->getInt());
$element->singlePurchasePriceNet->setInt($item->purchasePrice->getInt());
$element->totalPurchasePriceNet->setInt($element->quantity * $item->purchasePrice->getInt());
$element->taxR = new FloatInt($taxCombination->taxCode->percentageInvoice);
$element->taxCode = $taxCombination->taxCode->abbr;
$element->fiAccount = $taxCombination->account;
$element->singleProfitNet->setInt($element->singleSalesPriceNet->getInt() - $element->singlePurchasePriceNet->getInt());
$element->totalProfitNet->setInt($element->totalSalesPriceNet->getInt() - $element->totalPurchasePriceNet->getInt());
// @todo the purchase price is based on lot/sn/avg prices if available
$element->singlePurchasePriceNet->value = $item->purchasePrice->value;
$element->totalPurchasePriceNet->value = (int) ($element->quantity->getNormalizedValue() * $item->purchasePrice->value);
$element->taxP = new FloatInt((int) (($code->percentageInvoice * $element->totalSalesPriceNet->getInt()) / 10000));
$element->taxR = new FloatInt($code->percentageInvoice);
$element->taxCode = $code->abbr;
$element->singleListPriceGross->setInt((int) ($element->singleListPriceNet->getInt() + $element->singleListPriceNet->getInt() * $element->taxR->getInt() / 10000));
$element->totalListPriceGross->setInt((int) ($element->totalListPriceNet->getInt() + $element->totalListPriceNet->getInt() * $element->taxR->getInt() / 10000));
$element->singleSalesPriceGross->setInt((int) ($element->singleSalesPriceNet->getInt() + $element->singleSalesPriceNet->getInt() * $element->taxR->getInt() / 10000));
$element->totalSalesPriceGross->setInt((int) ($element->totalSalesPriceNet->getInt() + $element->totalSalesPriceNet->getInt() * $element->taxR->getInt() / 10000));
$element->singlePurchasePriceGross->setInt((int) ($element->singlePurchasePriceNet->getInt() + $element->singlePurchasePriceNet->getInt() * $element->taxR->getInt() / 10000));
$element->totalPurchasePriceGross->setInt((int) ($element->totalPurchasePriceNet->getInt() + $element->totalPurchasePriceNet->getInt() * $element->taxR->getInt() / 10000));
$element->singleProfitGross->setInt($element->singleSalesPriceGross->getInt() - $element->singlePurchasePriceGross->getInt());
$element->totalProfitGross->setInt($element->quantity * ($element->totalSalesPriceGross->getInt() - $element->totalPurchasePriceGross->getInt()));
$element->singlePurchasePriceGross->value = (int) \round($element->singlePurchasePriceNet->value + $element->singlePurchasePriceNet->value * $element->taxR->value / 10000, 0);
$element->totalPurchasePriceGross->value = (int) \round($element->totalPurchasePriceNet->value + $element->totalPurchasePriceNet->value * $element->taxR->value / 10000, 0);
if ($element->bill->id !== 0
&& $item->getAttribute('subscription')->value->getValue() === 1
@ -281,8 +319,7 @@ class BillElement implements \JsonSerializable
$element->subscription->bill = $element->bill->id;
$element->subscription->item = $element->item->id;
$element->subscription->start = new \DateTime('now'); // @todo change to bill performanceDate
$element->subscription->end = new SmartDateTime('now'); // @todo depends on subscription type
$element->subscription->end->smartModify(m: 1);
$element->subscription->end = (new SmartDateTime('now'))->smartModify(m: 1); // @todo depends on subscription type
$element->subscription->quantity = $element->quantity;
$element->subscription->autoRenew = $item->getAttribute('subscription_renewal_type')->value->getValue() === 1;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -37,10 +37,10 @@ final class PaymentTermL11nMapper extends DataMapperFactory
* @since 1.0.0
*/
public const COLUMNS = [
'billing_payment_term_l11n_id' => ['name' => 'billing_payment_term_l11n_id', 'type' => 'int', 'internal' => 'id'],
'billing_payment_term_l11n_name' => ['name' => 'billing_payment_term_l11n_name', 'type' => 'string', 'internal' => 'content', 'autocomplete' => true],
'billing_payment_term_l11n_term' => ['name' => 'billing_payment_term_l11n_term', 'type' => 'int', 'internal' => 'ref'],
'billing_payment_term_l11n_language' => ['name' => 'billing_payment_term_l11n_language', 'type' => 'string', 'internal' => 'language'],
'billing_payment_term_l11n_id' => ['name' => 'billing_payment_term_l11n_id', 'type' => 'int', 'internal' => 'id'],
'billing_payment_term_l11n_name' => ['name' => 'billing_payment_term_l11n_name', 'type' => 'string', 'internal' => 'content', 'autocomplete' => true],
'billing_payment_term_l11n_term' => ['name' => 'billing_payment_term_l11n_term', 'type' => 'int', 'internal' => 'ref'],
'billing_payment_term_l11n_language' => ['name' => 'billing_payment_term_l11n_language', 'type' => 'string', 'internal' => 'language'],
];
/**

View File

@ -37,8 +37,8 @@ final class PaymentTermMapper extends DataMapperFactory
* @since 1.0.0
*/
public const COLUMNS = [
'billing_payment_term_id' => ['name' => 'billing_payment_term_id', 'type' => 'int', 'internal' => 'id'],
'billing_payment_term_code' => ['name' => 'billing_payment_term_code', 'type' => 'string', 'internal' => 'title', 'autocomplete' => true],
'billing_payment_term_id' => ['name' => 'billing_payment_term_id', 'type' => 'int', 'internal' => 'id'],
'billing_payment_term_code' => ['name' => 'billing_payment_term_code', 'type' => 'string', 'internal' => 'title', 'autocomplete' => true],
];
/**
@ -54,7 +54,7 @@ final class PaymentTermMapper extends DataMapperFactory
'self' => 'billing_payment_term_l11n_term',
'column' => 'content',
'external' => null,
]
],
];
/**

View File

@ -50,6 +50,7 @@ class Price implements \JsonSerializable
public Item $item;
public AttributeValue $itemsalesgroup;
public AttributeValue $itemproductgroup;
public AttributeValue $itemsegment;
@ -76,20 +77,22 @@ class Price implements \JsonSerializable
public int $type = PriceType::SALES;
public int $quantity = 0;
public FloatInt $quantity;
public FloatInt $price;
public int $priceNew = 0;
public FloatInt $priceNew;
public int $discount = 0;
public FloatInt $discount;
public int $discountPercentage = 0;
public FloatInt $discountPercentage;
public int $bonus = 0;
public FloatInt $bonus;
public bool $multiply = false;
public bool $isAdditive = false;
public string $currency = ISO4217CharEnum::_EUR;
public ?\DateTime $start = null;
@ -103,12 +106,12 @@ class Price implements \JsonSerializable
*/
public function __construct()
{
$this->item = new NullItem();
$this->item = new NullItem();
$this->itemsalesgroup = new NullAttributeValue();
$this->itemproductgroup = new NullAttributeValue();
$this->itemsegment = new NullAttributeValue();
$this->itemsection = new NullAttributeValue();
$this->itemtype = new NullAttributeValue();
$this->itemproductgroup = new NullAttributeValue();
$this->itemsegment = new NullAttributeValue();
$this->itemsection = new NullAttributeValue();
$this->itemtype = new NullAttributeValue();
$this->client = new NullClient();
$this->clientgroup = new NullAttributeValue();
@ -118,19 +121,12 @@ class Price implements \JsonSerializable
$this->supplier = new NullSupplier();
$this->price = new FloatInt();
}
/**
* Get id.
*
* @return int Model id
*
* @since 1.0.0
*/
public function getId() : int
{
return $this->id;
$this->price = new FloatInt();
$this->quantity = new FloatInt();
$this->priceNew = new FloatInt();
$this->discount = new FloatInt();
$this->discountPercentage = new FloatInt();
$this->bonus = new FloatInt();
}
/**

View File

@ -42,34 +42,34 @@ final class PriceMapper extends DataMapperFactory
* @since 1.0.0
*/
public const COLUMNS = [
'billing_price_id' => ['name' => 'billing_price_id', 'type' => 'int', 'internal' => 'id'],
'billing_price_name' => ['name' => 'billing_price_name', 'type' => 'string', 'internal' => 'name'],
'billing_price_promocode' => ['name' => 'billing_price_promocode', 'type' => 'string', 'internal' => 'promocode'],
'billing_price_item' => ['name' => 'billing_price_item', 'type' => 'int', 'internal' => 'item'],
'billing_price_itemsegment' => ['name' => 'billing_price_itemsegment', 'type' => 'int', 'internal' => 'itemsegment'],
'billing_price_itemsection' => ['name' => 'billing_price_itemsection', 'type' => 'int', 'internal' => 'itemsection'],
'billing_price_itemsalesgroup' => ['name' => 'billing_price_itemsalesgroup', 'type' => 'int', 'internal' => 'itemsalesgroup'],
'billing_price_itemproductgroup' => ['name' => 'billing_price_itemproductgroup', 'type' => 'int', 'internal' => 'itemproductgroup'],
'billing_price_itemtype' => ['name' => 'billing_price_itemtype', 'type' => 'int', 'internal' => 'itemtype'],
'billing_price_client' => ['name' => 'billing_price_client', 'type' => 'int', 'internal' => 'client'],
'billing_price_clientsegment' => ['name' => 'billing_price_clientsegment', 'type' => 'int', 'internal' => 'clientsegment'],
'billing_price_clientsection' => ['name' => 'billing_price_clientsection', 'type' => 'int', 'internal' => 'clientsection'],
'billing_price_clientgroup' => ['name' => 'billing_price_clientgroup', 'type' => 'int', 'internal' => 'clientgroup'],
'billing_price_clienttype' => ['name' => 'billing_price_clienttype', 'type' => 'int', 'internal' => 'clienttype'],
'billing_price_clientcountry' => ['name' => 'billing_price_clientcountry', 'type' => 'string', 'internal' => 'clientcountry'],
'billing_price_supplier' => ['name' => 'billing_price_supplier', 'type' => 'int', 'internal' => 'supplier'],
'billing_price_unit' => ['name' => 'billing_price_unit', 'type' => 'int', 'internal' => 'unit'],
'billing_price_type' => ['name' => 'billing_price_type', 'type' => 'int', 'internal' => 'type'],
'billing_price_quantity' => ['name' => 'billing_price_quantity', 'type' => 'int', 'internal' => 'quantity'],
'billing_price_price' => ['name' => 'billing_price_price', 'type' => 'Serializable', 'internal' => 'price'],
'billing_price_price_new' => ['name' => 'billing_price_price_new', 'type' => 'int', 'internal' => 'priceNew'],
'billing_price_discount' => ['name' => 'billing_price_discount', 'type' => 'int', 'internal' => 'discount'],
'billing_price_discountp' => ['name' => 'billing_price_discountp', 'type' => 'int', 'internal' => 'discountPercentage'],
'billing_price_bonus' => ['name' => 'billing_price_bonus', 'type' => 'int', 'internal' => 'bonus'],
'billing_price_multiply' => ['name' => 'billing_price_multiply', 'type' => 'bool', 'internal' => 'multiply'],
'billing_price_currency' => ['name' => 'billing_price_currency', 'type' => 'string', 'internal' => 'currency'],
'billing_price_start' => ['name' => 'billing_price_start', 'type' => 'DateTime', 'internal' => 'start'],
'billing_price_end' => ['name' => 'billing_price_end', 'type' => 'DateTime', 'internal' => 'end'],
'billing_price_id' => ['name' => 'billing_price_id', 'type' => 'int', 'internal' => 'id'],
'billing_price_name' => ['name' => 'billing_price_name', 'type' => 'string', 'internal' => 'name'],
'billing_price_promocode' => ['name' => 'billing_price_promocode', 'type' => 'string', 'internal' => 'promocode'],
'billing_price_item' => ['name' => 'billing_price_item', 'type' => 'int', 'internal' => 'item'],
'billing_price_itemsegment' => ['name' => 'billing_price_itemsegment', 'type' => 'int', 'internal' => 'itemsegment'],
'billing_price_itemsection' => ['name' => 'billing_price_itemsection', 'type' => 'int', 'internal' => 'itemsection'],
'billing_price_itemsalesgroup' => ['name' => 'billing_price_itemsalesgroup', 'type' => 'int', 'internal' => 'itemsalesgroup'],
'billing_price_itemproductgroup' => ['name' => 'billing_price_itemproductgroup', 'type' => 'int', 'internal' => 'itemproductgroup'],
'billing_price_itemtype' => ['name' => 'billing_price_itemtype', 'type' => 'int', 'internal' => 'itemtype'],
'billing_price_client' => ['name' => 'billing_price_client', 'type' => 'int', 'internal' => 'client'],
'billing_price_clientsegment' => ['name' => 'billing_price_clientsegment', 'type' => 'int', 'internal' => 'clientsegment'],
'billing_price_clientsection' => ['name' => 'billing_price_clientsection', 'type' => 'int', 'internal' => 'clientsection'],
'billing_price_clientgroup' => ['name' => 'billing_price_clientgroup', 'type' => 'int', 'internal' => 'clientgroup'],
'billing_price_clienttype' => ['name' => 'billing_price_clienttype', 'type' => 'int', 'internal' => 'clienttype'],
'billing_price_clientcountry' => ['name' => 'billing_price_clientcountry', 'type' => 'string', 'internal' => 'clientcountry'],
'billing_price_supplier' => ['name' => 'billing_price_supplier', 'type' => 'int', 'internal' => 'supplier'],
'billing_price_unit' => ['name' => 'billing_price_unit', 'type' => 'int', 'internal' => 'unit'],
'billing_price_type' => ['name' => 'billing_price_type', 'type' => 'int', 'internal' => 'type'],
'billing_price_quantity' => ['name' => 'billing_price_quantity', 'type' => 'Serializable', 'internal' => 'quantity'],
'billing_price_price' => ['name' => 'billing_price_price', 'type' => 'Serializable', 'internal' => 'price'],
'billing_price_price_new' => ['name' => 'billing_price_price_new', 'type' => 'Serializable', 'internal' => 'priceNew'],
'billing_price_discount' => ['name' => 'billing_price_discount', 'type' => 'Serializable', 'internal' => 'discount'],
'billing_price_discountp' => ['name' => 'billing_price_discountp', 'type' => 'Serializable', 'internal' => 'discountPercentage'],
'billing_price_bonus' => ['name' => 'billing_price_bonus', 'type' => 'Serializable', 'internal' => 'bonus'],
'billing_price_multiply' => ['name' => 'billing_price_multiply', 'type' => 'bool', 'internal' => 'multiply'],
'billing_price_currency' => ['name' => 'billing_price_currency', 'type' => 'string', 'internal' => 'currency'],
'billing_price_start' => ['name' => 'billing_price_start', 'type' => 'DateTime', 'internal' => 'start'],
'billing_price_end' => ['name' => 'billing_price_end', 'type' => 'DateTime', 'internal' => 'end'],
];
/**

View File

@ -42,10 +42,10 @@ final class PurchaseBillMapper extends BillMapper
*/
public static function getPurchaseBeforePivot(
mixed $pivot,
string $column = null,
?string $column = null,
int $limit = 50,
int $depth = 3,
Builder $query = null
?Builder $query = null
) : array
{
return self::getAll()
@ -61,10 +61,10 @@ final class PurchaseBillMapper extends BillMapper
*/
public static function getPurchaseAfterPivot(
mixed $pivot,
string $column = null,
?string $column = null,
int $limit = 50,
int $depth = 3,
Builder $query = null
?Builder $query = null
) : array
{
return self::getAll()

View File

@ -42,10 +42,10 @@ final class SalesBillMapper extends BillMapper
*/
public static function getSalesBeforePivot(
mixed $pivot,
string $column = null,
?string $column = null,
int $limit = 50,
int $depth = 3,
Builder $query = null
?Builder $query = null
) : array
{
return self::getAll()
@ -61,10 +61,10 @@ final class SalesBillMapper extends BillMapper
*/
public static function getSalesAfterPivot(
mixed $pivot,
string $column = null,
?string $column = null,
int $limit = 50,
int $depth = 3,
Builder $query = null
?Builder $query = null
) : array
{
return self::getAll()
@ -132,7 +132,7 @@ final class SalesBillMapper extends BillMapper
AND billing_bill_performance_date <= '{$end->format('Y-m-d H:i:s')}';
SQL;
$query = new Builder(self::$db);
$query = new Builder(self::$db);
$result = $query->raw($sql)->execute()->fetchAll(\PDO::FETCH_ASSOC);
return isset($result[0]['net_count'])
@ -380,7 +380,7 @@ final class SalesBillMapper extends BillMapper
ORDER BY year ASC, month ASC;
SQL;
$query = new Builder(self::$db);
$query = new Builder(self::$db);
$result = $query->raw($sql)->execute()->fetchAll(\PDO::FETCH_ASSOC);
return $result ?? [];
@ -406,7 +406,7 @@ final class SalesBillMapper extends BillMapper
ORDER BY year ASC, month ASC;
SQL;
$query = new Builder(self::$db);
$query = new Builder(self::$db);
$result = $query->raw($sql)->execute()->fetchAll(\PDO::FETCH_ASSOC);
return $result ?? [];
@ -424,7 +424,7 @@ final class SalesBillMapper extends BillMapper
AND billing_bill_performance_date <= '{$end->format('Y-m-d H:i:s')}';
SQL;
$query = new Builder(self::$db);
$query = new Builder(self::$db);
$result = $query->raw($sql)->execute()->fetchAll(\PDO::FETCH_ASSOC);
return new FloatInt((int) ($result[0]['net_sales'] ?? 0));
@ -439,7 +439,7 @@ final class SalesBillMapper extends BillMapper
WHERE billing_bill_element_item = {$item}
SQL;
$query = new Builder(self::$db);
$query = new Builder(self::$db);
$result = $query->raw($sql)->execute()->fetchAll(\PDO::FETCH_ASSOC);
return new FloatInt((int) ($result[0]['net_sales'] ?? 0));
@ -461,7 +461,7 @@ final class SalesBillMapper extends BillMapper
LIMIT 1;
SQL;
$query = new Builder(self::$db);
$query = new Builder(self::$db);
$result = $query->raw($sql)->execute()->fetchAll(\PDO::FETCH_ASSOC);
return isset($result[0]['billing_bill_created_at'])
@ -480,7 +480,7 @@ final class SalesBillMapper extends BillMapper
AND billing_bill_performance_date <= '{$end->format('Y-m-d H:i:s')}';
SQL;
$query = new Builder(self::$db);
$query = new Builder(self::$db);
$result = $query->raw($sql)->execute()->fetchAll(\PDO::FETCH_ASSOC);
return new FloatInt((int) ($result[0]['net_sales'] ?? 0));
@ -494,7 +494,7 @@ final class SalesBillMapper extends BillMapper
WHERE billing_bill_client = {$client};
SQL;
$query = new Builder(self::$db);
$query = new Builder(self::$db);
$result = $query->raw($sql)->execute()->fetchAll(\PDO::FETCH_ASSOC);
return new FloatInt((int) ($result[0]['net_sales'] ?? 0));
@ -515,7 +515,7 @@ final class SalesBillMapper extends BillMapper
LIMIT 1;
SQL;
$query = new Builder(self::$db);
$query = new Builder(self::$db);
$result = $query->raw($sql)->execute()->fetchAll(\PDO::FETCH_ASSOC);
return isset($result[0]['billing_bill_created_at'])

View File

@ -37,10 +37,10 @@ final class ShippingTermL11nMapper extends DataMapperFactory
* @since 1.0.0
*/
public const COLUMNS = [
'billing_shipping_term_l11n_id' => ['name' => 'billing_shipping_term_l11n_id', 'type' => 'int', 'internal' => 'id'],
'billing_shipping_term_l11n_name' => ['name' => 'billing_shipping_term_l11n_name', 'type' => 'string', 'internal' => 'content', 'autocomplete' => true],
'billing_shipping_term_l11n_term' => ['name' => 'billing_shipping_term_l11n_term', 'type' => 'int', 'internal' => 'ref'],
'billing_shipping_term_l11n_language' => ['name' => 'billing_shipping_term_l11n_language', 'type' => 'string', 'internal' => 'language'],
'billing_shipping_term_l11n_id' => ['name' => 'billing_shipping_term_l11n_id', 'type' => 'int', 'internal' => 'id'],
'billing_shipping_term_l11n_name' => ['name' => 'billing_shipping_term_l11n_name', 'type' => 'string', 'internal' => 'content', 'autocomplete' => true],
'billing_shipping_term_l11n_term' => ['name' => 'billing_shipping_term_l11n_term', 'type' => 'int', 'internal' => 'ref'],
'billing_shipping_term_l11n_language' => ['name' => 'billing_shipping_term_l11n_language', 'type' => 'string', 'internal' => 'language'],
];
/**

View File

@ -37,8 +37,8 @@ final class ShippingTermMapper extends DataMapperFactory
* @since 1.0.0
*/
public const COLUMNS = [
'billing_shipping_term_id' => ['name' => 'billing_shipping_term_id', 'type' => 'int', 'internal' => 'id'],
'billing_shipping_term_code' => ['name' => 'billing_shipping_term_code', 'type' => 'string', 'internal' => 'title', 'autocomplete' => true],
'billing_shipping_term_id' => ['name' => 'billing_shipping_term_id', 'type' => 'int', 'internal' => 'id'],
'billing_shipping_term_code' => ['name' => 'billing_shipping_term_code', 'type' => 'string', 'internal' => 'title', 'autocomplete' => true],
];
/**
@ -54,7 +54,7 @@ final class ShippingTermMapper extends DataMapperFactory
'self' => 'billing_shipping_term_l11n_term',
'column' => 'content',
'external' => null,
]
],
];
/**

View File

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

View File

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

View File

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

View File

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

View File

@ -16,6 +16,8 @@ namespace Modules\Billing\Models\Tax;
use Modules\Attribute\Models\AttributeValue;
use Modules\Attribute\Models\NullAttributeValue;
use Modules\Finance\Models\NullTaxCode;
use Modules\Finance\Models\TaxCode;
/**
* Billing class.
@ -41,9 +43,7 @@ class TaxCombination implements \JsonSerializable
public AttributeValue $itemCode;
public string $taxCode = '';
// @todo consider to add the tax code object directly, it is annoying to make a manuall mapper call which is often required afterwards.
public TaxCode $taxCode;
public int $taxType = BillTaxType::SALES;
@ -69,6 +69,7 @@ class TaxCombination implements \JsonSerializable
public function __construct()
{
$this->itemCode = new NullAttributeValue();
$this->taxCode = new NullTaxCode();
}
/**
@ -77,7 +78,7 @@ class TaxCombination implements \JsonSerializable
public function toArray() : array
{
return [
'id' => $this->id,
'id' => $this->id,
];
}

View File

@ -15,8 +15,9 @@ declare(strict_types=1);
namespace Modules\Billing\Models\Tax;
use Modules\ClientManagement\Models\Attribute\ClientAttributeValueMapper;
use Modules\Finance\Models\TaxCodeMapper;
use Modules\ItemManagement\Models\Attribute\ItemAttributeValueMapper;
use Modules\SupplierManagement\Models\SupplierAttributeValueMapper;
use Modules\SupplierManagement\Models\Attribute\SupplierAttributeValueMapper;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
/**
@ -73,6 +74,12 @@ final class TaxCombinationMapper extends DataMapperFactory
'mapper' => ItemAttributeValueMapper::class,
'external' => 'billing_tax_item_code',
],
'taxCode' => [
'mapper' => TaxCodeMapper::class,
'external' => 'billing_tax_code',
'by' => 'abbr',
'column' => 'abbr',
],
];
/**

View File

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

View File

@ -40,15 +40,15 @@ return ['Billing' => [
'Due' => 'Fällig',
'Email' => 'Email',
'Freightage' => 'Fracht',
'Gross' => 'Grob',
'Gross' => 'Brutto',
'Invoice' => 'Rechnung',
'Item' => 'Artikel',
'Items' => 'Produkte',
'Language' => 'Sprache',
'Log' => 'Protokoll',
'Logs' => 'Protokoll',
'Logs' => 'Protokolle',
'Media' => 'Medien',
'MoneyTransfer' => 'Geldüberweisung',
'MoneyTransfer' => 'Überweisung',
'Name' => 'Name',
'Net' => 'Netz',
'Offer' => 'Angebot',
@ -59,7 +59,7 @@ return ['Billing' => [
'Prepaid' => 'Vorausbezahlt',
'Preview' => 'Vorschau',
'Price' => 'Preis',
'Profit' => 'Profitieren',
'Profit' => 'Gewinn',
'Quantity' => 'Menge',
'Recipient' => 'Empfänger',
'Select' => 'Wählen',
@ -68,15 +68,17 @@ return ['Billing' => [
'Supplier' => 'Anbieter',
'SupplierID' => 'Lieferanten ID',
'Tax' => 'Steuer',
'TaxP' => 'Steuer %',
'Margin' => 'Marge',
'TermsOfDelivery' => 'Lieferbedingungen',
'Total' => 'Gesamt',
'Type' => 'Typ',
'Types' => 'Typen',
'Upload' => 'Hochladen',
'Zip' => 'Zip',
'Files' => 'Files',
'PaymentTerms' => 'Zahlungsbedingungen',
'ShippingTerms' => 'Lieferbedingungen',
'PaymentTerm' => 'Zahlungsbedingung',
'ShippingTerm' => 'Lieferbedingung',
'Files' => 'Files',
'PaymentTerms' => 'Zahlungsbedingungen',
'ShippingTerms' => 'Lieferbedingungen',
'PaymentTerm' => 'Zahlungsbedingung',
'ShippingTerm' => 'Lieferbedingung',
]];

View File

@ -68,15 +68,17 @@ return ['Billing' => [
'Supplier' => 'Supplier',
'SupplierID' => 'Supplier ID',
'Tax' => 'Tax',
'TaxP' => 'Tax %',
'Margin' => 'Margin',
'TermsOfDelivery' => 'Terms Of Delivery',
'Total' => 'Total',
'Type' => 'Type',
'Types' => 'Types',
'Upload' => 'Upload',
'Zip' => 'Zip',
'Files' => 'Files',
'PaymentTerms' => 'Payment Terms',
'ShippingTerms' => 'Shipping Terms',
'PaymentTerm' => 'Payment Term',
'ShippingTerm' => 'Shipping Term',
'Files' => 'Files',
'PaymentTerms' => 'Payment Terms',
'ShippingTerms' => 'Shipping Terms',
'PaymentTerm' => 'Payment Term',
'ShippingTerm' => 'Shipping Term',
]];

View File

@ -20,10 +20,10 @@ use phpOMS\Localization\ISO4217Enum;
use phpOMS\Localization\ISO639Enum;
use phpOMS\Uri\UriFactory;
$countryCodes = ISO3166TwoEnum::getConstants();
$countries = ISO3166NameEnum::getConstants();
$languages = ISO639Enum::getConstants();
$currencies = ISO4217Enum::getConstants();
$countryCodes = ISO3166TwoEnum::getConstants();
$countries = ISO3166NameEnum::getConstants();
$languages = ISO639Enum::getConstants();
$currencies = ISO4217Enum::getConstants();
/**
* @var \phpOMS\Views\View $this
@ -32,7 +32,7 @@ $media = $this->data['media'] ?? [];
/** @var \Modules\Billing\Models\Bill $bill */
$bill = $this->getData('bill') ?? new NullBill();
$elements = $bill->getElements();
$elements = $bill->elements;
$billTypes = $this->data['billtypes'] ?? [];
@ -41,7 +41,7 @@ $archive = $bill->getFileByTypeName('original');
/** @var \Modules\Auditor\Models\Audit */
$logs = $this->data['logs'] ?? [];
$editable = $bill->id === 0 || \in_array($bill->getStatus(), [BillStatus::DRAFT, BillStatus::UNPARSED]);
$editable = $bill->id === 0 || \in_array($bill->status, [BillStatus::DRAFT, BillStatus::UNPARSED]);
$disabled = $editable ? '' : ' disabled';
$isNew = $archive->id === 0;
@ -82,7 +82,7 @@ echo $this->data['nav']->render(); ?>
<label for="iCurrency"><?= $this->getHtml('Currency'); ?></label>
<select id="iCurrency" name="bill_currency"<?= $disabled; ?>>
<?php foreach ($currencies as $code => $currency) : $code = \substr($code, 1); ?>
<option value="<?= $this->printHtml($code); ?>"<?= $code === $bill->getCurrency() ? ' selected' : ''; ?>><?= $this->printHtml($currency); ?>
<option value="<?= $this->printHtml($code); ?>"<?= $code === $bill->currency ? ' selected' : ''; ?>><?= $this->printHtml($currency); ?>
<?php endforeach; ?>
</select>
</div>
@ -119,7 +119,7 @@ echo $this->data['nav']->render(); ?>
</div>
<?php if (($bill->client?->id ?? 0) > 0) : ?>
<div class="ipt-second">
<a class="button" href="<?= UriFactory::build('{/base}/sales/client/profile?id=' . $bill->client->id); ?>"><?= $this->getHtml('Client'); ?></a>
<a class="button" href="<?= UriFactory::build('{/base}/sales/client/view?id=' . $bill->client->id); ?>"><?= $this->getHtml('Client'); ?></a>
</div>
<?php endif; ?>
</div>
@ -284,13 +284,14 @@ echo $this->data['nav']->render(); ?>
<td>
<td style="min-width:150px"><?= $this->getHtml('Item'); ?>
<td class="wf-100" style="min-width:150px"><?= $this->getHtml('Name'); ?>
<td style="min-width:50px"><?= $this->getHtml('Quantity'); ?>
<td style="min-width:75px"><?= $this->getHtml('Quantity'); ?>
<td style="min-width:90px"><?= $this->getHtml('Discount'); ?>
<td style="min-width:90px"><?= $this->getHtml('DiscountP'); ?>
<td style="min-width:90px"><?= $this->getHtml('Bonus'); ?>
<td style="min-width:90px"><?= $this->getHtml('Tax'); ?>
<td style="min-width:75px"><?= $this->getHtml('Bonus'); ?>
<td style="min-width:90px"><?= $this->getHtml('Price'); ?>
<td style="min-width:75px"><?= $this->getHtml('TaxP'); ?>
<td><?= $this->getHtml('Net'); ?>
<td><?= $this->getHtml('Margin'); ?>
<tbody class="oms-ordercontainer">
<?php if ($editable) : ?>
<template class="oms-invoice-add">
@ -302,14 +303,15 @@ echo $this->data['nav']->render(); ?>
<td><span class="input">
<button type="button" formaction="">
<label><i class="g-icon">book</i></label>
</button><input type="text" autocomplete="off"></span>
<td><textarea autocomplete="off"></textarea>
<td><input type="number" step="any" value="" autocomplete="off">
<td><input type="number" step="0.01" value="" autocomplete="off">
<td><input type="number" min="-100" max="100" step="0.01" value="" autocomplete="off">
<td><input type="number" step="0.01" value="" autocomplete="off">
<td><input type="number" step="0.01" value="" autocomplete="off">
<td><input type="number" step="0.01" value="" autocomplete="off">
</button><input name="item_number" type="text" autocomplete="off"></span>
<td><textarea name="item_description" autocomplete="off"></textarea>
<td><input name="item_quantity" type="number" step="any" value="" autocomplete="off">
<td><input name="item_discountp" type="number" step="0.01" value="" autocomplete="off">
<td><input name="item_discountr" type="number" min="-100" max="100" step="0.01" value="" autocomplete="off">
<td><input name="item_bonus" type="number" step="0.01" value="" autocomplete="off">
<td><input name="item_price" type="number" step="0.01" value="" autocomplete="off">
<td><input name="item_taxr" type="number" step="0.01" value="" autocomplete="off">
<td>
<td>
</tr>
</template>
@ -321,31 +323,49 @@ echo $this->data['nav']->render(); ?>
<i class="g-icon order-down">expand_more</i>
<i class="g-icon btn remove-form">close</i>
<?php endif; ?>
<td><span class="input"><button type="button" formaction=""><i class="g-icon">book</i></button><input name="" type="text" value="<?= $element->itemNumber; ?>"<?= $disabled; ?>></span>
<td><textarea<?= $disabled; ?>><?= $element->itemName; ?></textarea>
<td><input name="" type="number" step="any" value="<?= $element->getQuantity(); ?>"<?= $disabled; ?>>
<td><input name="" type="number" step="0.01"<?= $disabled; ?>>
<td><input name="" type="number" step="0.01"<?= $disabled; ?>>
<td><input name="" type="number" min="-100" max="100" step="0.01"<?= $disabled; ?>>
<td><input name="" type="number" step="0.01"<?= $disabled; ?>>
<td><input name="" type="number" step="0.01" value="<?= $element->singleSalesPriceNet->getFloat(); ?>"<?= $disabled; ?>>
<td><?= $this->getCurrency($element->totalSalesPriceNet); ?>
<td><span class="input">
<button type="button" formaction="">
<i class="g-icon">book</i>
</button><input name="item_number" autocomplete="off" type="text" value="<?= $element->itemNumber; ?>"<?= $disabled; ?>></span>
<td><textarea name="item_description" autocomplete="off"<?= $disabled; ?>><?= $element->itemName; ?></textarea>
<td><input name="item_quantity" autocomplete="off" type="number" step="any" value="<?= $element->quantity->sub($element->discountQ)->getAmount($element->container->quantityDecimals); ?>"<?= $disabled; ?>>
<td><input name="item_discountp" autocomplete="off" type="number" step="0.01" value="<?= $element->singleDiscountP->getAmount(); ?>"<?= $disabled; ?>>
<td><input name="item_discountr" autocomplete="off" type="number" step="0.01" value="<?= $element->singleDiscountR->getAmount(); ?>"<?= $disabled; ?>>
<td><input name="item_bonus" autocomplete="off" type="number" min="-100" max="100" step="0.01" value="<?= $element->discountQ->getAmount($element->container->quantityDecimals); ?>"<?= $disabled; ?>>
<td><input name="item_price" autocomplete="off" type="number" step="0.01" value="<?= $element->singleSalesPriceNet->getFloat(); ?>"<?= $disabled; ?>>
<td><input name="item_taxr" autocomplete="off" type="number" step="0.01" value="<?= $element->taxR->getAmount(); ?>"<?= $disabled; ?>>
<td><?= $this->getCurrency($element->totalSalesPriceNet, symbol: ''); ?>
<td><?= \number_format($element->totalSalesPriceNet->value === 0 ? 0 : (1 - $element->totalPurchasePriceNet->value / $element->totalSalesPriceNet->value) * 100, 2); ?>%
<?php endforeach; ?>
<?php if ($editable) : ?>
<tr data-id="0">
<td><i class="g-icon order-up">expand_less</i>
<i class="g-icon order-down">expand_more</i>
<i class="g-icon btn remove-form">close</i>
<td><span class="input"><button type="button" formaction=""><i class="g-icon">book</i></button><input type="text" autocomplete="off"></span>
<td><textarea autocomplete="off"></textarea>
<td><input type="number" step="any" value="" autocomplete="off">
<td><input type="number" step="0.01" value="" autocomplete="off">
<td><input type="number" min="-100" max="100" step="0.01" value="" autocomplete="off">
<td><input type="number" step="0.01" value="" autocomplete="off">
<td><input type="number" step="0.01" value="" autocomplete="off">
<td><input type="number" step="0.01" value="" autocomplete="off">
<td><span class="input">
<button type="button" formaction="">
<i class="g-icon">book</i></button><input name="item_number" type="text" autocomplete="off"></span>
<td><textarea name="item_description" autocomplete="off"></textarea>
<td><input name="item_quantity" type="number" step="any" value="" autocomplete="off">
<td><input name="item_discountp" type="number" step="0.01" value="" autocomplete="off">
<td><input name="item_discountr" type="number" min="-100" max="100" step="0.01" value="" autocomplete="off">
<td><input name="item_bonus" type="number" step="0.01" value="" autocomplete="off">
<td><input name="item_price" type="number" step="0.01" value="" autocomplete="off">
<td><input name="item_taxr" type="number" step="0.01" value="" autocomplete="off">
<td>
<td>
<?php endif; ?>
<tfoot>
<tr class="highlight-2">
<td colspan="3"><?= $this->getHtml('Total'); ?>
<td>
<td><?= $bill->netDiscount->getAmount(2); ?>
<td><?= \number_format($bill->netDiscount->value === 0 ? 0 : ($bill->netDiscount->value / ($bill->netSales->value + $bill->netDiscount->value)) * 100, 2); ?>%
<td>
<td>
<td><?= $bill->taxP->getAmount(2); ?>
<td><?= $bill->netSales->getAmount(2); ?>
<td><?= \number_format($bill->netSales->value === 0 ? 0 : (1 - $bill->netCosts->value / $bill->netSales->value) * 100, 2); ?>%
</table>
</div>
</section>
@ -518,7 +538,7 @@ echo $this->data['nav']->render(); ?>
<tbody>
<?php
foreach ($logs as $audit) :
$url = UriFactory::build('{/base}/admin/audit/single?id=' . $audit->id);
$url = UriFactory::build('{/base}/admin/audit/view?id=' . $audit->id);
?>
<tr data-href="<?= $url; ?>">
<td><a href="<?= $url; ?>"><?= $audit->id; ?></a>
@ -532,7 +552,7 @@ echo $this->data['nav']->render(); ?>
href="<?= UriFactory::build('{/base}/admin/account/settings?id=' . $audit->createdBy->id); ?>"><?= $this->printHtml(
$this->renderUserName('%3$s %2$s %1$s', [$audit->createdBy->name1, $audit->createdBy->name2, $audit->createdBy->name3, $audit->createdBy->login])
); ?></a>
<td><a href="<?= $url; ?>"><?= $audit->createdAt->format('Y-m-d'); ?></a>
<td><a href="<?= $url; ?>"><?= $audit->createdAt->format('Y-m-d H:i'); ?></a>
<?php endforeach; ?>
</table>
</div>

View File

@ -15,7 +15,7 @@ declare(strict_types=1);
use phpOMS\Uri\UriFactory;
/** @var \phpOMS\Localization\BaseStringL11nType */
$type = $this->data['type'];
$type = $this->data['type'];
/** @var \phpOMS\Views\View $this */
echo $this->data['nav']->render(); ?>

View File

@ -163,7 +163,7 @@ echo $this->data['nav']->render(); ?>
</label>
<td><a href="<?= $url; ?>"><?= $value->getNumber(); ?></a>
<td><a href="<?= $url; ?>"><?= $value->type->getL11n(); ?></a>
<td><a class="content" href="<?= $supplier = UriFactory::build('purchase/supplier/profile?{?}&id=' . $value->supplier->id); ?>"><?= $value->supplier->number; ?></a>
<td><a class="content" href="<?= $supplier = UriFactory::build('purchase/supplier/view?{?}&id=' . $value->supplier->id); ?>"><?= $value->supplier->number; ?></a>
<td><a class="content" href="<?= $supplier; ?>"><?= $this->printHtml($value->billTo); ?></a>
<td><a href="<?= $url;
?>"><?= $value->billAddress; ?></a>

View File

@ -23,12 +23,12 @@ include __DIR__ . '/../../../Media/Theme/Backend/template-functions.php';
/** @var \Modules\Billing\Models\Bill $bill */
$bill = $this->data['bill'];
$elements = $bill->getElements();
$elements = $bill->elements;
$billTypes = $this->data['billtypes'] ?? [];
$originalType = $this->data['originalType'];
$original = $bill->getFileByType($originalType);
$original = $bill->getFileByType($originalType);
/** @var \Modules\Auditor\Models\Audit */
$logs = $this->data['logs'] ?? [];
@ -302,7 +302,7 @@ echo $this->data['nav']->render(); ?>
<tbody>
<?php
foreach ($logs as $audit) :
$url = UriFactory::build('{/base}/admin/audit/single?id=' . $audit->id);
$url = UriFactory::build('{/base}/admin/audit/view?id=' . $audit->id);
?>
<tr data-href="<?= $url; ?>">
<td><a href="<?= $url; ?>"><?= $audit->id; ?></a>

View File

@ -174,7 +174,7 @@ echo $this->data['nav']->render(); ?>
</label>
<td><a href="<?= $url; ?>"><?= $value->getNumber(); ?></a>
<td><a href="<?= $url; ?>"><?= $value->type->getL11n(); ?></a>
<td><a class="content" href="<?= $client = UriFactory::build('sales/client/profile?{?}&id=' . $value->client->id); ?>"><?= $value->client->number; ?></a>
<td><a class="content" href="<?= $client = UriFactory::build('sales/client/view?{?}&id=' . $value->client->id); ?>"><?= $value->client->number; ?></a>
<td><a class="content" href="<?= $client; ?>"><?= $this->printHtml($value->billTo); ?></a>
<td><a href="<?= $url;
?>"><?= $value->billAddress; ?></a>

View File

@ -15,7 +15,7 @@ declare(strict_types=1);
use phpOMS\Uri\UriFactory;
/** @var \phpOMS\Localization\BaseStringL11nType */
$type = $this->data['type'];
$type = $this->data['type'];
/** @var \phpOMS\Views\View $this */
echo $this->data['nav']->render(); ?>

View File

@ -165,7 +165,7 @@ echo $this->data['nav']->render(); ?>
</label>
<td><a href="<?= $url; ?>"><?= $value->getNumber(); ?></a>
<td><a href="<?= $url; ?>"><?= $value->type->getL11n(); ?></a>
<td><a class="content" href="<?= $supplier = UriFactory::build('purchase/supplier/profile?{?}&id=' . $value->supplier->id); ?>"><?= $value->supplier->number; ?></a>
<td><a class="content" href="<?= $supplier = UriFactory::build('purchase/supplier/view?{?}&id=' . $value->supplier->id); ?>"><?= $value->supplier->number; ?></a>
<td><a class="content" href="<?= $supplier; ?>"><?= $this->printHtml($value->billTo); ?></a>
<td><a href="<?= $url;
?>"><?= $value->billAddress; ?></a>

View File

@ -23,13 +23,13 @@ include __DIR__ . '/../../../Media/Theme/Backend/template-functions.php';
*/
$bill = $this->data['bill'];
$elements = $bill->getElements();
$elements = $bill->elements;
$previewType = $this->data['previewType'];
$originalType = $this->data['originalType'];
$billPdf = $bill->getFileByType($previewType);
$original = $bill->getFileByType($originalType);
$media = $bill->getMedia();
$media = $bill->files;
echo $this->data['nav']->render(); ?>
@ -298,7 +298,7 @@ echo $this->data['nav']->render(); ?>
<?php foreach ($media as $file) :
$url = $file->extension === 'collection'
? UriFactory::build('{/base}/media/list?path=' . \rtrim($file->getVirtualPath(), '/') . '/' . $file->name)
: UriFactory::build('{/base}/media/single?id=' . $file->id
: UriFactory::build('{/base}/media/view?id=' . $file->id
. '&path={?path}' . (
$file->id === 0
? '/' . $file->name

View File

@ -75,8 +75,8 @@ final class Autoloader
*/
public static function defaultAutoloader(string $class) : void
{
$class = \ltrim($class, '\\');
$class = \strtr($class, '_\\', '//');
$class = \ltrim($class, '\\');
$class = \strtr($class, '_\\', '//');
if (\stripos($class, 'Web/Backend') !== false || \stripos($class, 'Web/Api') !== false) {
$class = \is_dir(__DIR__ . '/Web') ? $class : \str_replace('Web/', 'MainRepository/Web/', $class);

View File

@ -1,4 +1,15 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\Billing\tests
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
\ini_set('memory_limit', '2048M');
@ -67,10 +78,10 @@ $GLOBALS['is_github'] = $IS_GITHUB;
$tmp = FileLogger::getInstance(__DIR__ . '/../Logs');
$CONFIG = [
'db' => [
'db' => [
'core' => [
'masters' => [
'admin' => [
'admin' => [
'db' => 'mysql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '3306', /* db host port */
@ -80,7 +91,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
'insert' => [
'insert' => [
'db' => 'mysql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '3306', /* db host port */
@ -90,7 +101,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
'select' => [
'select' => [
'db' => 'mysql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '3306', /* db host port */
@ -100,7 +111,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
'update' => [
'update' => [
'db' => 'mysql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '3306', /* db host port */
@ -110,7 +121,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
'delete' => [
'delete' => [
'db' => 'mysql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '3306', /* db host port */
@ -120,7 +131,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
'schema' => [
'schema' => [
'db' => 'mysql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '3306', /* db host port */
@ -132,7 +143,7 @@ $CONFIG = [
],
],
'postgresql' => [
'admin' => [
'admin' => [
'db' => 'pgsql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '5432', /* db host port */
@ -142,7 +153,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
'insert' => [
'insert' => [
'db' => 'pgsql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '5432', /* db host port */
@ -152,7 +163,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
'select' => [
'select' => [
'db' => 'pgsql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '5432', /* db host port */
@ -162,7 +173,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
'update' => [
'update' => [
'db' => 'pgsql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '5432', /* db host port */
@ -172,7 +183,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
'delete' => [
'delete' => [
'db' => 'pgsql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '5432', /* db host port */
@ -182,7 +193,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
'schema' => [
'schema' => [
'db' => 'pgsql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '5432', /* db host port */
@ -194,37 +205,37 @@ $CONFIG = [
],
],
'sqlite' => [
'admin' => [
'admin' => [
'db' => 'sqlite', /* db type */
'database' => __DIR__ . '/../Karaka/phpOMS/Localization/Defaults/localization.sqlite', /* db name */
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
'insert' => [
'insert' => [
'db' => 'sqlite', /* db type */
'database' => __DIR__ . '/../Karaka/phpOMS/Localization/Defaults/localization.sqlite', /* db name */
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
'select' => [
'select' => [
'db' => 'sqlite', /* db type */
'database' => __DIR__ . '/../Karaka/phpOMS/Localization/Defaults/localization.sqlite', /* db name */
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
'update' => [
'update' => [
'db' => 'sqlite', /* db type */
'database' => __DIR__ . '/../Karaka/phpOMS/Localization/Defaults/localization.sqlite', /* db name */
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
'delete' => [
'delete' => [
'db' => 'sqlite', /* db type */
'database' => __DIR__ . '/../Karaka/phpOMS/Localization/Defaults/localization.sqlite', /* db name */
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
'schema' => [
'schema' => [
'db' => 'sqlite', /* db type */
'database' => __DIR__ . '/../Karaka/phpOMS/Localization/Defaults/localization.sqlite', /* db name */
'weight' => 1000, /* db table prefix */
@ -232,7 +243,7 @@ $CONFIG = [
],
],
'mssql' => [
'admin' => [
'admin' => [
'db' => 'mssql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '1433', /* db host port */
@ -242,7 +253,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
'insert' => [
'insert' => [
'db' => 'mssql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '1433', /* db host port */
@ -252,7 +263,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
'select' => [
'select' => [
'db' => 'mssql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '1433', /* db host port */
@ -262,7 +273,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
'update' => [
'update' => [
'db' => 'mssql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '1433', /* db host port */
@ -272,7 +283,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
'delete' => [
'delete' => [
'db' => 'mssql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '1433', /* db host port */
@ -282,7 +293,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
'schema' => [
'schema' => [
'db' => 'mssql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '1433', /* db host port */
@ -322,16 +333,16 @@ $CONFIG = [
'password' => '123456',
],
],
'log' => [
'log' => [
'file' => [
'path' => __DIR__ . '/Logs',
],
],
'page' => [
'page' => [
'root' => '/',
'https' => false,
],
'app' => [
'app' => [
'path' => __DIR__,
'default' => [
'app' => 'Backend',
@ -350,7 +361,7 @@ $CONFIG = [
],
],
],
'socket' => [
'socket' => [
'master' => [
'host' => '127.0.0.1',
'limit' => 300,
@ -360,7 +371,7 @@ $CONFIG = [
'language' => [
'en',
],
'apis' => [
'apis' => [
],
];

View File

@ -17,7 +17,6 @@ namespace Modules\Billing\tests\Controller\Api;
use phpOMS\Message\Http\HttpRequest;
use phpOMS\Message\Http\HttpResponse;
use phpOMS\Message\Http\RequestStatusCode;
use phpOMS\Uri\HttpUri;
use phpOMS\Utils\RnG\DateTime;
trait ApiBillControllerTrait
@ -25,7 +24,7 @@ trait ApiBillControllerTrait
public function testBillCreate() : void
{
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
@ -53,7 +52,7 @@ trait ApiBillControllerTrait
public function testBillElementCreate() : void
{
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
@ -73,7 +72,7 @@ trait ApiBillControllerTrait
public function testBillArchiveCreate() : void
{
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
@ -87,7 +86,7 @@ trait ApiBillControllerTrait
public function testBillNoteCreate() : void
{
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = \mt_rand(2, 5);
@ -107,7 +106,7 @@ trait ApiBillControllerTrait
public function testBillCreateInvalidData() : void
{
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('invalid', '1');
@ -123,7 +122,7 @@ trait ApiBillControllerTrait
public function testBillElementCreateInvalidData() : void
{
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('invalid', '1');

View File

@ -18,7 +18,6 @@ use phpOMS\Message\Http\HttpRequest;
use phpOMS\Message\Http\HttpResponse;
use phpOMS\Message\Http\RequestStatusCode;
use phpOMS\System\File\Local\Directory;
use phpOMS\Uri\HttpUri;
use phpOMS\Utils\TestUtils;
trait ApiPurchaseControllerTrait
@ -44,7 +43,7 @@ trait ApiPurchaseControllerTrait
$file = $invoiceDocs[$i];
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request = new HttpRequest();
$request->header->account = 1;

View File

@ -59,14 +59,14 @@ final class ApiControllerTest extends \PHPUnit\Framework\TestCase
protected string $appName = 'Api';
};
$this->app->dbPool = $GLOBALS['dbpool'];
$this->app->unitId = 1;
$this->app->accountManager = new AccountManager($GLOBALS['session']);
$this->app->appSettings = new CoreSettings();
$this->app->moduleManager = new ModuleManager($this->app, __DIR__ . '/../../../../Modules/');
$this->app->dispatcher = new Dispatcher($this->app);
$this->app->eventManager = new EventManager($this->app->dispatcher);
$this->app->l11nManager = new L11nManager();
$this->app->dbPool = $GLOBALS['dbpool'];
$this->app->unitId = 1;
$this->app->accountManager = new AccountManager($GLOBALS['session']);
$this->app->appSettings = new CoreSettings();
$this->app->moduleManager = new ModuleManager($this->app, __DIR__ . '/../../../../Modules/');
$this->app->dispatcher = new Dispatcher($this->app);
$this->app->eventManager = new EventManager($this->app->dispatcher);
$this->app->l11nManager = new L11nManager();
$this->app->eventManager->importFromFile(__DIR__ . '/../../../../Web/Api/Hooks.php');
$account = new Account();

View File

@ -15,10 +15,7 @@ declare(strict_types=1);
namespace Modules\Billing\tests\Models;
use Modules\Billing\Models\Bill;
use Modules\Billing\Models\BillElement;
use Modules\Billing\Models\BillStatus;
use Modules\Billing\Models\NullBillType;
use phpOMS\Localization\ISO4217CharEnum;
/**
* @internal
@ -51,8 +48,6 @@ final class BillTest extends \PHPUnit\Framework\TestCase
self::assertNull($this->bill->send);
self::assertNull($this->bill->client);
self::assertNull($this->bill->supplier);
self::assertEquals([], $this->bill->getVouchers());
self::assertEquals([], $this->bill->getTrackings());
self::assertInstanceOf('\Modules\Media\Models\NullMedia', $this->bill->getFileByType(0));
self::assertEquals('', $this->bill->shipTo);
@ -82,7 +77,7 @@ final class BillTest extends \PHPUnit\Framework\TestCase
self::assertEquals('', $this->bill->paymentText);
self::assertEquals(0, $this->bill->terms);
self::assertEquals('', $this->bill->termsText);
self::assertEquals(0, $this->bill->shipping);
self::assertEquals(0, $this->bill->shippingTerms);
self::assertEquals('', $this->bill->shippingText);
}
@ -96,94 +91,44 @@ final class BillTest extends \PHPUnit\Framework\TestCase
self::assertEquals(\date('Y') . \date('m') . \date('d') . '-0', $this->bill->getNumber());
}
/**
* @covers Modules\Billing\Models\Bill
* @group module
*/
public function testStatusInputOutput() : void
{
$this->bill->setStatus(BillStatus::ACTIVE);
self::assertEquals(BillStatus::ACTIVE, $this->bill->getStatus());
}
/**
* @covers Modules\Billing\Models\Bill
* @group module
*/
public function testCurrencyInputOutput() : void
{
$this->bill->setCurrency(ISO4217CharEnum::_USD);
self::assertEquals(ISO4217CharEnum::_USD, $this->bill->getCurrency());
}
/**
* @covers Modules\Billing\Models\Bill
* @group module
*/
public function testVoucherInputOutput() : void
{
$this->bill->addVoucher('TEST');
self::assertEquals(['TEST'], $this->bill->getVouchers());
}
/**
* @covers Modules\Billing\Models\Bill
* @group module
*/
public function testTrackingInputOutput() : void
{
$this->bill->addTracking('TEST');
self::assertEquals(['TEST'], $this->bill->getTrackings());
}
/**
* @covers Modules\Billing\Models\Bill
* @group module
*/
public function testElementInputOutput() : void
{
$this->bill->addElement(new BillElement());
self::assertCount(1, $this->bill->getElements());
}
/**
* @covers Modules\Billing\Models\Bill
* @group module
*/
public function testSerialize() : void
{
$this->bill->number = '123456';
$this->bill->type = new NullBillType(2);
$this->bill->shipTo = 'To';
$this->bill->shipFAO = 'FAO';
$this->bill->shipAddress = 'Address';
$this->bill->shipCity = 'City';
$this->bill->shipZip = 'Zip';
$this->bill->shipCountry = 'Country';
$this->bill->billTo = 'To';
$this->bill->billFAO = 'FAO';
$this->bill->billAddress = 'Address';
$this->bill->billCity = 'City';
$this->bill->billZip = 'Zip';
$this->bill->billCountry = 'Country';
$this->bill->number = '123456';
$this->bill->type = new NullBillType(2);
$this->bill->shipTo = 'To';
$this->bill->shipFAO = 'FAO';
$this->bill->shipAddress = 'Address';
$this->bill->shipCity = 'City';
$this->bill->shipZip = 'Zip';
$this->bill->shipCountry = 'Country';
$this->bill->billTo = 'To';
$this->bill->billFAO = 'FAO';
$this->bill->billAddress = 'Address';
$this->bill->billCity = 'City';
$this->bill->billZip = 'Zip';
$this->bill->billCountry = 'Country';
self::assertEquals(
[
'id' => 0,
'number' => '123456',
'type' => $this->bill->type,
'shipTo' => 'To',
'shipFAO' => 'FAO',
'shipAddress' => 'Address',
'shipCity' => 'City',
'shipZip' => 'Zip',
'shipCountry' => 'Country',
'billTo' => 'To',
'billFAO' => 'FAO',
'billAddress' => 'Address',
'billCity' => 'City',
'billZip' => 'Zip',
'billCountry' => 'Country',
'id' => 0,
'number' => '123456',
'type' => $this->bill->type,
'shipTo' => 'To',
'shipFAO' => 'FAO',
'shipAddress' => 'Address',
'shipCity' => 'City',
'shipZip' => 'Zip',
'shipCountry' => 'Country',
'billTo' => 'To',
'billFAO' => 'FAO',
'billAddress' => 'Address',
'billCity' => 'City',
'billZip' => 'Zip',
'billCountry' => 'Country',
],
$this->bill->jsonSerialize()
);