fix demoSetup

This commit is contained in:
Dennis Eichhorn 2023-04-16 01:55:34 +02:00
parent ac6b22c47f
commit 9c5db3832e
20 changed files with 462 additions and 100 deletions

View File

@ -14,8 +14,6 @@ declare(strict_types=1);
namespace Modules\Billing\Admin\Install; namespace Modules\Billing\Admin\Install;
use Model\Setting;
use Model\SettingMapper;
use Modules\Billing\Models\SettingsEnum; use Modules\Billing\Models\SettingsEnum;
use phpOMS\Application\ApplicationAbstract; use phpOMS\Application\ApplicationAbstract;
@ -43,29 +41,26 @@ class Media
{ {
$media = \Modules\Media\Admin\Installer::installExternal($app, ['path' => __DIR__ . '/Media.install.json']); $media = \Modules\Media\Admin\Installer::installExternal($app, ['path' => __DIR__ . '/Media.install.json']);
$preivewType = (int) \reset($media['type'][0]); \Modules\Admin\Admin\Installer::installExternal(
$originalType = (int) \reset($media['type'][1]); $app,
[
$setting = new Setting(); 'data' => [
SettingMapper::create()->execute( [
$setting->with( 'type' => 'setting',
0, 'name' => SettingsEnum::PREVIEW_MEDIA_TYPE,
SettingsEnum::PREVIEW_MEDIA_TYPE, 'content' => (string) $media['type'][0]['id'],
(string) $preivewType, 'pattern' => '\\d+',
'\\d+', 'module' => 'Billing'
module: 'Billing' ],
) [
); 'type' => 'setting',
'name' => SettingsEnum::ORIGINAL_MEDIA_TYPE,
$setting = new Setting(); 'content' => (string) $media['type'][1]['id'],
SettingMapper::create()->execute( 'pattern' => '\\d+',
$setting->with( 'module' => 'Billing'
0, ]
SettingsEnum::ORIGINAL_MEDIA_TYPE, ]
(string) $originalType, ]
'\\d+',
module: 'Billing'
)
); );
} }
} }

View File

@ -388,6 +388,15 @@
"primary": true, "primary": true,
"autoincrement": true "autoincrement": true
}, },
"billing_bill_sequence": {
"name": "billing_bill_sequence",
"type": "INT",
"null": false,
"multi_autoincrement": [
"billing_bill_unit",
"billing_bill_type"
]
},
"billing_bill_number": { "billing_bill_number": {
"name": "billing_bill_number", "name": "billing_bill_number",
"type": "VARCHAR(255)", "type": "VARCHAR(255)",
@ -664,6 +673,80 @@
"type": "VARCHAR(255)", "type": "VARCHAR(255)",
"default": null, "default": null,
"null": true "null": true
},
"billing_bill_unit": {
"name": "billing_bill_unit",
"type": "INT",
"null": false,
"foreignTable": "unit",
"foreignKey": "unit_id"
}
}
},
"billing_subscription": {
"description": "https://learn.microsoft.com/en-us/graph/outlook-schedule-recurring-events",
"name": "billing_subscription",
"fields": {
"billing_subscription_id": {
"name": "billing_subscription_id",
"type": "INT",
"null": false,
"primary": true,
"autoincrement": true
},
"billing_subscription_status": {
"name": "billing_subscription_status",
"type": "TINYINT(1)",
"null": false
},
"billing_subscription_start": {
"name": "billing_subscription_start",
"type": "DATETIME",
"null": false
},
"billing_subscription_end": {
"name": "billing_subscription_end",
"type": "DATETIME",
"null": true,
"default": null
},
"billing_subscription_price": {
"name": "billing_subscription_price",
"type": "BIGINT",
"null": false
},
"billing_subscription_quantity": {
"name": "billing_subscription_quantity",
"type": "BIGINT",
"null": false
},
"billing_subscription_bill": {
"name": "billing_subscription_bill",
"type": "INT",
"null": true,
"default": null,
"foreignTable": "billing_bill",
"foreignKey": "billing_bill_id"
},
"billing_subscription_item": {
"name": "billing_subscription_item",
"type": "INT",
"null": false,
"foreignTable": "itemmgmt_item",
"foreignKey": "itemmgmt_item_id"
},
"billing_subscription_autorenew": {
"name": "billing_subscription_autorenew",
"type": "TINYINT(1)",
"null": false
},
"billing_subscription_client": {
"name": "billing_subscription_client",
"type": "INT",
"null": true,
"default": null,
"foreignTable": "clientmgmt_client",
"foreignKey": "clientmgmt_client_id"
} }
} }
}, },
@ -686,7 +769,17 @@
"name": "billing_bill_element_item", "name": "billing_bill_element_item",
"type": "INT", "type": "INT",
"null": true, "null": true,
"default": null "default": null,
"foreignTable": "itemmgmt_item",
"foreignKey": "itemmgmt_item_id"
},
"billing_bill_element_subscription": {
"name": "billing_bill_element_subscription",
"type": "INT",
"null": true,
"default": null,
"foreignTable": "billing_subscription",
"foreignKey": "billing_subscription_id"
}, },
"billing_bill_element_item_segment": { "billing_bill_element_item_segment": {
"name": "billing_bill_element_item_segment", "name": "billing_bill_element_item_segment",
@ -1184,46 +1277,6 @@
} }
} }
}, },
"billing_bill_subscription": {
"description": "https://learn.microsoft.com/en-us/graph/outlook-schedule-recurring-events",
"name": "billing_bill_subscription",
"fields": {
"billing_bill_subscription_id": {
"name": "billing_bill_subscription_id",
"type": "INT",
"null": false,
"primary": true,
"autoincrement": true
},
"billing_bill_subscription_status": {
"name": "billing_bill_subscription_status",
"type": "TINYINT(1)",
"null": false
},
"billing_bill_subscription_bill": {
"name": "billing_bill_subscription_bill",
"type": "INT",
"null": false,
"foreignTable": "billing_bill",
"foreignKey": "billing_bill_id"
},
"billing_bill_subscription_schedule": {
"name": "billing_bill_subscription_schedule",
"type": "INT",
"null": false,
"foreignTable": "schedule",
"foreignKey": "schedule_id"
},
"billing_bill_subscription_account": {
"name": "billing_bill_subscription_account",
"type": "INT",
"null": true,
"default": null,
"foreignTable": "account",
"foreignKey": "account_id"
}
}
},
"billing_bill_responsible": { "billing_bill_responsible": {
"name": "billing_bill_responsible", "name": "billing_bill_responsible",
"fields": { "fields": {

View File

@ -0,0 +1,11 @@
CREATE TRIGGER update_billing_bill_sequence
BEFORE INSERT ON billing_bill
FOR EACH ROW BEGIN
SET NEW.billing_bill_sequence = (
SELECT COALESCE(MAX(billing_bill_sequence), 0) + 1
FROM billing_bill
WHERE billing_bill_unit = NEW.billing_bill_unit
AND billing_bill_type = NEW.billing_bill_type
LIMIT 1
);
END;

16
Admin/Install/db.psql.sql Normal file
View File

@ -0,0 +1,16 @@
CREATE SEQUENCE billing_bill_sequence;
CREATE OR REPLACE FUNCTION update_billing_bill_sequence()
RETURNS TRIGGER AS
$$
BEGIN
NEW.billing_bill_sequence = nextval('billing_bill_sequence') WHERE billing_bill_unit = NEW.billing_bill_unit;
RETURN NEW;
END;
$$
LANGUAGE plpgsql;
CREATE TRIGGER update_sequence_trigger
BEFORE INSERT ON billing_bill
FOR EACH ROW
EXECUTE FUNCTION update_billing_bill_sequence();

View File

@ -17,6 +17,7 @@ namespace Modules\Billing\Admin;
use Modules\Attribute\Models\AttributeTypeMapper; use Modules\Attribute\Models\AttributeTypeMapper;
use Modules\Billing\Models\BillTransferType; use Modules\Billing\Models\BillTransferType;
use Modules\ClientManagement\Models\ClientAttributeTypeMapper; use Modules\ClientManagement\Models\ClientAttributeTypeMapper;
use Modules\ItemManagement\Models\ItemAttributeTypeMapper;
use Modules\SupplierManagement\Models\SupplierAttributeTypeMapper; use Modules\SupplierManagement\Models\SupplierAttributeTypeMapper;
use phpOMS\Application\ApplicationAbstract; use phpOMS\Application\ApplicationAbstract;
use phpOMS\Config\SettingsInterface; use phpOMS\Config\SettingsInterface;
@ -258,8 +259,8 @@ final class Installer extends InstallerAbstract
/** @var \Modules\Billing\Controller\ApiController $module */ /** @var \Modules\Billing\Controller\ApiController $module */
$module = $app->moduleManager->getModuleInstance('Billing'); $module = $app->moduleManager->getModuleInstance('Billing');
/** @var \Modules\Attribute\Models\AttributeType $AttributeSales */ /** @var \Modules\Attribute\Models\ItemAttributeTypeMapper $itemAttributeSales */
$AttributeSales = AttributeTypeMapper::get() $itemAttributeSales = ItemAttributeTypeMapper::get()
->with('defaults') ->with('defaults')
->where('name', 'sales_tax_code') ->where('name', 'sales_tax_code')
->execute(); ->execute();
@ -277,7 +278,7 @@ final class Installer extends InstallerAbstract
->execute(); ->execute();
foreach ($taxes as $tax) { foreach ($taxes as $tax) {
$itemValue = $AttributeSales->getDefaultByValue($tax['item_code']); $itemValue = $itemAttributeSales->getDefaultByValue($tax['item_code']);
$accountValue = $tax['type'] === 1 $accountValue = $tax['type'] === 1
? $clientAttributeSales->getDefaultByValue($tax['account_code']) ? $clientAttributeSales->getDefaultByValue($tax['account_code'])
: $supplierAttributeSales->getDefaultByValue($tax['account_code']); : $supplierAttributeSales->getDefaultByValue($tax['account_code']);

View File

@ -168,6 +168,15 @@ final class ApiBillController extends Controller
{ {
$this->createModel($request->header->account, $bill, BillMapper::class, 'bill', $request->getOrigin()); $this->createModel($request->header->account, $bill, BillMapper::class, 'bill', $request->getOrigin());
// We ned to get the bill again since the bill has a trigger which is executed on insert
// @todo: consider to remove the trigger and select the latest bill here and add + 1 to the new sequence since we have to tdo an update anyways
/** @var Bill $bill */
$tmp = BillMapper::get()
->where('id', $bill->getId())
->execute();
$bill->sequence = $tmp->sequence;
$old = clone $bill; $old = clone $bill;
$bill->buildNumber(); // The bill id is part of the number $bill->buildNumber(); // The bill id is part of the number
$this->updateModel($request->header->account, $old, $bill, BillMapper::class, 'bill', $request->getOrigin()); $this->updateModel($request->header->account, $old, $bill, BillMapper::class, 'bill', $request->getOrigin());
@ -194,6 +203,7 @@ final class ApiBillController extends Controller
// @todo: validate vat before creation // @todo: validate vat before creation
$bill = new Bill(); $bill = new Bill();
$bill->createdBy = new NullAccount($request->header->account); $bill->createdBy = new NullAccount($request->header->account);
$bill->unit = $client->unit ?? $this->app->unitId;
$bill->billDate = new \DateTime('now'); // @todo: Date of payment $bill->billDate = new \DateTime('now'); // @todo: Date of payment
$bill->performanceDate = new \DateTime('now'); // @todo: Date of payment $bill->performanceDate = new \DateTime('now'); // @todo: Date of payment
$bill->accountNumber = $client->number; $bill->accountNumber = $client->number;
@ -279,8 +289,12 @@ final class ApiBillController extends Controller
{ {
$taxCode = $this->app->moduleManager->get('Billing', 'ApiTax')->getTaxCodeFromClientItem($client, $item, $request->getCountry()); $taxCode = $this->app->moduleManager->get('Billing', 'ApiTax')->getTaxCodeFromClientItem($client, $item, $request->getCountry());
$element = BillElement::fromItem($item, $taxCode, $request->getDataInt('quantity') ?? 1); $element = BillElement::fromItem(
$element->bill = $request->getDataInt('bill') ?? 0; $item,
$taxCode,
$request->getDataInt('quantity') ?? 1,
$bill->getId()
);
return $element; return $element;
} }
@ -327,6 +341,7 @@ final class ApiBillController extends Controller
// @todo: use defaultInvoiceAddress or mainAddress. also consider to use billto1, billto2, billto3 (for multiple lines e.g. name2, fao etc.) // @todo: use defaultInvoiceAddress or mainAddress. also consider to use billto1, billto2, billto3 (for multiple lines e.g. name2, fao etc.)
/** @var \Modules\SupplierManagement\Models\Supplier|\Modules\ClientManagement\Models\Client $account */ /** @var \Modules\SupplierManagement\Models\Supplier|\Modules\ClientManagement\Models\Client $account */
$bill = new Bill(); $bill = new Bill();
$bill->unit = $account->unit ?? $this->app->unitId;
$bill->createdBy = new NullAccount($request->header->account); $bill->createdBy = new NullAccount($request->header->account);
$bill->type = $billType; $bill->type = $billType;
$bill->billTo = $request->getDataString('billto') ?? ( $bill->billTo = $request->getDataString('billto') ?? (

View File

@ -54,10 +54,10 @@ final class ApiPurchaseController extends Controller
*/ */
public function apiSupplierBillUpload(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void public function apiSupplierBillUpload(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void
{ {
$originalType = $request->getDataInt('type') ?? (int) $this->app->appSettings->get( $originalType = $request->getDataInt('type') ?? ((int) $this->app->appSettings->get(
names: SettingsEnum::ORIGINAL_MEDIA_TYPE, names: SettingsEnum::ORIGINAL_MEDIA_TYPE,
module: self::NAME module: self::NAME
)->content; )->content);
/** @var \Modules\Billing\Models\BillType $purchaseTransferType */ /** @var \Modules\Billing\Models\BillType $purchaseTransferType */
$purchaseTransferType = BillTypeMapper::get() $purchaseTransferType = BillTypeMapper::get()

View File

@ -128,11 +128,11 @@ final class BackendController extends Controller
/** @var \Modules\Auditor\Models\Auditor[] $logsBill */ /** @var \Modules\Auditor\Models\Auditor[] $logsBill */
$logsBill = AuditMapper::getAll() $logsBill = AuditMapper::getAll()
->with('createdBy') ->with('createdBy')
->where('module', 'Billing') ->where('module', 'Billing')
->where('type', StringUtils::intHash(BillMapper::class)) ->where('type', StringUtils::intHash(BillMapper::class))
->where('ref', $bill->getId()) ->where('ref', $bill->getId())
->execute(); ->execute();
/** @var \Modules\Auditor\Models\Auditor[] $logsElements */ /** @var \Modules\Auditor\Models\Auditor[] $logsElements */
$logsElements = AuditMapper::getAll() $logsElements = AuditMapper::getAll()

View File

@ -45,6 +45,21 @@ class Bill implements \JsonSerializable
*/ */
protected int $id = 0; protected int $id = 0;
/**
* Sequence.
*
* Incrementing value depending on multiple columns e.g.:
* id & unit
* id & unit & type
* id & unit & year
*
* @var int
* @since 1.0.0
*/
public int $sequence = 0;
public int $unit = 0;
public int $source = 0; public int $source = 0;
/** /**
@ -497,6 +512,7 @@ class Bill implements \JsonSerializable
'{m}', '{m}',
'{d}', '{d}',
'{id}', '{id}',
'{sequence}',
'{type}', '{type}',
], ],
[ [
@ -504,6 +520,7 @@ class Bill implements \JsonSerializable
$this->createdAt->format('m'), $this->createdAt->format('m'),
$this->createdAt->format('d'), $this->createdAt->format('d'),
$this->id, $this->id,
$this->sequence,
$this->type->getId(), $this->type->getId(),
], ],
$this->type->numberFormat $this->type->numberFormat

View File

@ -50,6 +50,8 @@ class BillElement implements \JsonSerializable
protected int $quantity = 0; protected int $quantity = 0;
public ?Subscription $subscription = null;
public Money $singleSalesPriceNet; public Money $singleSalesPriceNet;
public Money $singleSalesPriceGross; public Money $singleSalesPriceGross;
@ -227,15 +229,17 @@ class BillElement implements \JsonSerializable
* @param Item $item Item * @param Item $item Item
* @param TaxCode $code Tax code used for gross amount calculation * @param TaxCode $code Tax code used for gross amount calculation
* @param int $quantity Quantity * @param int $quantity Quantity
* @param int $bill Bill
* *
* @return self * @return self
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function fromItem(Item $item, TaxCode $code, int $quantity = 1) : self public static function fromItem(Item $item, TaxCode $code, int $quantity = 1, int $bill = 0) : self
{ {
$element = new self(); $element = new self();
$element->item = $item->getId(); $element->bill = $bill;
$element->item = empty($item->getId()) ? null : $item->getId();
$element->itemNumber = $item->number; $element->itemNumber = $item->number;
$element->itemName = $item->getL11n('name1')->description; $element->itemName = $item->getL11n('name1')->description;
$element->itemDescription = $item->getL11n('description_short')->description; $element->itemDescription = $item->getL11n('description_short')->description;
@ -267,6 +271,20 @@ class BillElement implements \JsonSerializable
$element->singleProfitGross->setInt($element->singleSalesPriceGross->getInt() - $element->singlePurchasePriceGross->getInt()); $element->singleProfitGross->setInt($element->singleSalesPriceGross->getInt() - $element->singlePurchasePriceGross->getInt());
$element->totalProfitGross->setInt($element->quantity * ($element->totalSalesPriceGross->getInt() - $element->totalPurchasePriceGross->getInt())); $element->totalProfitGross->setInt($element->quantity * ($element->totalSalesPriceGross->getInt() - $element->totalPurchasePriceGross->getInt()));
if (!empty($element->bill)
&& $item->getAttribute('subscription')?->value->getValue() === 1
) {
$element->subscription = new Subscription();
$element->subscription->bill = $element->bill;
$element->subscription->item = $element->item;
$element->subscription->start = $element->quantity;
$element->subscription->end = $element->quantity;
$element->subscription->quantity = $element->quantity;
$element->subscription->autoRenew = $item->getAttribute('subscription_renewal_type')->value->getValue() === 1
? true
: false;
}
return $element; return $element;
} }

View File

@ -83,6 +83,19 @@ final class BillElementMapper extends DataMapperFactory
], ],
]; ];
/**
* Has one relation.
*
* @var array<string, array{mapper:class-string, external:string, by?:string, column?:string, conditional?:bool}>
* @since 1.0.0
*/
public const OWNS_ONE = [
'subscription' => [
'mapper' => SubscriptionMapper::class,
'external' => 'billing_bill_element_subscription',
],
];
/** /**
* Primary field name. * Primary field name.
* *

View File

@ -44,6 +44,7 @@ class BillMapper extends DataMapperFactory
*/ */
public const COLUMNS = [ public const COLUMNS = [
'billing_bill_id' => ['name' => 'billing_bill_id', 'type' => 'int', 'internal' => 'id'], 'billing_bill_id' => ['name' => 'billing_bill_id', 'type' => 'int', 'internal' => 'id'],
'billing_bill_sequence' => ['name' => 'billing_bill_sequence', 'type' => 'int', 'internal' => 'sequence'],
'billing_bill_number' => ['name' => 'billing_bill_number', 'type' => 'string', 'internal' => 'number'], 'billing_bill_number' => ['name' => 'billing_bill_number', 'type' => 'string', 'internal' => 'number'],
'billing_bill_type' => ['name' => 'billing_bill_type', 'type' => 'int', 'internal' => 'type'], 'billing_bill_type' => ['name' => 'billing_bill_type', 'type' => 'int', 'internal' => 'type'],
'billing_bill_template' => ['name' => 'billing_bill_template', 'type' => 'int', 'internal' => 'template'], 'billing_bill_template' => ['name' => 'billing_bill_template', 'type' => 'int', 'internal' => 'template'],
@ -90,6 +91,7 @@ class BillMapper extends DataMapperFactory
'billing_bill_date' => ['name' => 'billing_bill_date', 'type' => 'DateTime', 'internal' => 'billDate'], '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_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_created_at' => ['name' => 'billing_bill_created_at', 'type' => 'DateTimeImmutable', 'internal' => 'createdAt', 'readonly' => true],
'billing_bill_unit' => ['name' => 'billing_bill_unit', 'type' => 'int', 'internal' => 'unit'],
]; ];
/** /**

View File

@ -0,0 +1,47 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\Billing\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\Billing\Models;
/**
* Null subscription class.
*
* @package Modules\Billing\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
final class NullSubscription extends Subscription
{
/**
* Constructor
*
* @param int $id Model id
*
* @since 1.0.0
*/
public function __construct(int $id = 0)
{
$this->id = $id;
parent::__construct();
}
/**
* {@inheritdoc}
*/
public function jsonSerialize() : mixed
{
return ['id' => $this->id];
}
}

View File

@ -14,9 +14,9 @@ declare(strict_types=1);
namespace Modules\Billing\Models\Price; namespace Modules\Billing\Models\Price;
use Modules\Attribute\Models\AttributeValueMapper;
use Modules\ClientManagement\Models\ClientAttributeValueMapper; use Modules\ClientManagement\Models\ClientAttributeValueMapper;
use Modules\ClientManagement\Models\ClientMapper; use Modules\ClientManagement\Models\ClientMapper;
use Modules\ItemManagement\Models\ItemAttributeValueMapper;
use Modules\ItemManagement\Models\ItemMapper; use Modules\ItemManagement\Models\ItemMapper;
use Modules\SupplierManagement\Models\SupplierMapper; use Modules\SupplierManagement\Models\SupplierMapper;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory; use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
@ -83,19 +83,19 @@ final class PriceMapper extends DataMapperFactory
'external' => 'billing_price_item', 'external' => 'billing_price_item',
], ],
'itemgroup' => [ 'itemgroup' => [
'mapper' => AttributeValueMapper::class, 'mapper' => ItemAttributeValueMapper::class,
'external' => 'billing_price_itemgroup', 'external' => 'billing_price_itemgroup',
], ],
'itemsegment' => [ 'itemsegment' => [
'mapper' => AttributeValueMapper::class, 'mapper' => ItemAttributeValueMapper::class,
'external' => 'billing_price_itemsegment', 'external' => 'billing_price_itemsegment',
], ],
'itemsection' => [ 'itemsection' => [
'mapper' => AttributeValueMapper::class, 'mapper' => ItemAttributeValueMapper::class,
'external' => 'billing_price_itemsection', 'external' => 'billing_price_itemsection',
], ],
'itemtype' => [ 'itemtype' => [
'mapper' => AttributeValueMapper::class, 'mapper' => ItemAttributeValueMapper::class,
'external' => 'billing_price_itemtype', 'external' => 'billing_price_itemtype',
], ],
'client' => [ 'client' => [

View File

@ -229,22 +229,34 @@ final class SalesBillMapper extends BillMapper
*/ */
public static function getItemTopClients(int $id, \DateTime $start, \DateTime $end, int $limit = 10) : array public static function getItemTopClients(int $id, \DateTime $start, \DateTime $end, int $limit = 10) : array
{ {
$query = ClientMapper::getQuery(); $query = new Builder(self::$db);
$query->selectAs('SUM(billing_bill_element_total_netsalesprice)', 'net_sales') $query->selectAs(ClientMapper::TABLE . '.clientmgmt_client_id', 'client')
->leftJoin(self::TABLE, self::TABLE . '_d1') ->selectAs('SUM(' . BillElementMapper::TABLE . '.billing_bill_element_total_netsalesprice)', 'net_sales')
->on(ClientMapper::TABLE . '_d1.clientmgmt_client_id', '=', self::TABLE . '_d1.billing_bill_client') ->from(ClientMapper::TABLE)
->leftJoin(BillElementMapper::TABLE, BillElementMapper::TABLE . '_d1') ->leftJoin( self::TABLE)
->on(self::TABLE . '_d1.billing_bill_id', '=', BillElementMapper::TABLE . '_d1.billing_bill_element_bill') ->on(ClientMapper::TABLE . '.clientmgmt_client_id', '=', self::TABLE . '.billing_bill_client')
->where(BillElementMapper::TABLE . '_d1.billing_bill_element_item', '=', $id) ->leftJoin(BillElementMapper::TABLE)
->andWhere(self::TABLE . '_d1.billing_bill_performance_date', '>=', $start) ->on(self::TABLE . '.billing_bill_id', '=', BillElementMapper::TABLE . '.billing_bill_element_bill')
->andWhere(self::TABLE . '_d1.billing_bill_performance_date', '<=', $end) ->where(BillElementMapper::TABLE . '.billing_bill_element_item', '=', $id)
->andWhere(self::TABLE . '.billing_bill_performance_date', '>=', $start)
->andWhere(self::TABLE . '.billing_bill_performance_date', '<=', $end)
->orderBy('net_sales', 'DESC') ->orderBy('net_sales', 'DESC')
->limit($limit) ->limit($limit)
->groupBy(ClientMapper::TABLE . '_d1.clientmgmt_client_id'); ->groupBy('client');
/** @var \Modules\ClientManagement\Models\Client[] $clients */ $stmt = $query->execute();
$clients = ClientMapper::getAll()->execute($query); $data = $stmt->fetchAll();
$data = ClientMapper::getRaw()->execute();
$clientIds = [];
foreach ($data as $client) {
$clientIds[] = $client['client'];
}
if (!empty($clientIds)) {
$clients = ClientMapper::getAll()
->where('id', $clientIds, 'IN')
->execute();
}
return [$clients, $data]; return [$clients, $data];
} }

94
Models/Subscription.php Normal file
View File

@ -0,0 +1,94 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\Billing\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\Billing\Models;
use phpOMS\Stdlib\Base\FloatInt;
/**
* Subscription class.
*
* @package Modules\Billing\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
class Subscription implements \JsonSerializable
{
/**
* ID.
*
* @var int
* @since 1.0.0
*/
protected int $id = 0;
public int $status = 0;
public \DateTime $start;
public ?\DateTime $end = null;
public FloatInt $price;
public int $bill = 0;
public int $item = 0;
public bool $autoRenew = false;
public int $client = 0;
public int $quantity = 0;
/**
* Constructor.
*
* @since 1.0.0
*/
public function __construct()
{
$price = new FloatInt();
}
/**
* Get id.
*
* @return int Model id
*
* @since 1.0.0
*/
public function getId() : int
{
return $this->id;
}
/**
* {@inheritdoc}
*/
public function toArray() : array
{
return [
'id' => $this->id,
];
}
/**
* {@inheritdoc}
*/
public function jsonSerialize() : mixed
{
return $this->toArray();
}
}

View File

@ -0,0 +1,66 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\Billing\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\Billing\Models;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
/**
* Mapper class.
*
* @package Modules\Billing\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @template T of Subscription
* @extends DataMapperFactory<T>
*/
final class SubscriptionMapper extends DataMapperFactory
{
/**
* Columns.
*
* @var array<string, array{name:string, type:string, internal:string, autocomplete?:bool, readonly?:bool, writeonly?:bool, annotations?:array}>
* @since 1.0.0
*/
public const COLUMNS = [
'billing_subscription_id' => ['name' => 'billing_subscription_id', 'type' => 'int', 'internal' => 'id'],
'billing_subscription_status' => ['name' => 'billing_subscription_status', 'type' => 'int', 'internal' => 'status'],
'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_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'],
'billing_subscription_client' => ['name' => 'billing_subscription_client', 'type' => 'int', 'internal' => 'client'],
];
/**
* Primary field name.
*
* @var string
* @since 1.0.0
*/
public const PRIMARYFIELD = 'billing_subscription_id';
/**
* Primary table.
*
* @var string
* @since 1.0.0
*/
public const TABLE = 'billing_subscription';
}

View File

@ -14,8 +14,8 @@ declare(strict_types=1);
namespace Modules\Billing\Models\Tax; namespace Modules\Billing\Models\Tax;
use Modules\Attribute\Models\AttributeValueMapper;
use Modules\ClientManagement\Models\ClientAttributeValueMapper; use Modules\ClientManagement\Models\ClientAttributeValueMapper;
use Modules\ItemManagement\Models\ItemAttributeValueMapper;
use Modules\SupplierManagement\Models\SupplierAttributeValueMapper; use Modules\SupplierManagement\Models\SupplierAttributeValueMapper;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory; use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
@ -70,7 +70,7 @@ final class TaxCombinationMapper extends DataMapperFactory
'external' => 'billing_tax_supplier_code', 'external' => 'billing_tax_supplier_code',
], ],
'itemCode' => [ 'itemCode' => [
'mapper' => AttributeValueMapper::class, 'mapper' => ItemAttributeValueMapper::class,
'external' => 'billing_tax_item_code', 'external' => 'billing_tax_item_code',
], ],
]; ];

View File

@ -40,6 +40,7 @@ return ['Billing' => [
'Created' => 'Created', 'Created' => 'Created',
'CreditCard' => 'CreditCard', 'CreditCard' => 'CreditCard',
'CreditNote' => 'Credit Note', 'CreditNote' => 'Credit Note',
'CreateBill' => 'Create Bill',
'Customers' => 'Customers', 'Customers' => 'Customers',
'Date' => 'Date', 'Date' => 'Date',
'Delivery' => 'Delivery', 'Delivery' => 'Delivery',

View File

@ -20,6 +20,7 @@
"Admin": "1.0.0", "Admin": "1.0.0",
"Sales": "1.0.0", "Sales": "1.0.0",
"Media": "1.0.0", "Media": "1.0.0",
"Finance": "1.0.0",
"Calendar": "1.0.0", "Calendar": "1.0.0",
"ItemManagement": "1.0.0", "ItemManagement": "1.0.0",
"ClientManagement": "1.0.0", "ClientManagement": "1.0.0",