From 293a3e060a76da6f36e8c79400d87735a34f1cfa Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Sun, 26 Mar 2023 22:54:09 +0000 Subject: [PATCH] fix registration, login and billing --- Admin/Install/db.json | 2 +- Controller/ApiBillController.php | 50 +++++++++++++++++++++++++++- Controller/ApiPriceController.php | 2 ++ Models/Bill.php | 12 +++++++ Models/BillElement.php | 54 +++++++++++++++++++++++++++++++ Models/BillElementMapper.php | 4 +++ 6 files changed, 122 insertions(+), 2 deletions(-) diff --git a/Admin/Install/db.json b/Admin/Install/db.json index 57ff707..84231e5 100755 --- a/Admin/Install/db.json +++ b/Admin/Install/db.json @@ -855,7 +855,7 @@ }, "billing_bill_element_tax_type": { "name": "billing_bill_element_tax_type", - "type": "INT", + "type": "VARCHAR(10)", "null": true, "default": null }, diff --git a/Controller/ApiBillController.php b/Controller/ApiBillController.php index 6877841..f491fa5 100755 --- a/Controller/ApiBillController.php +++ b/Controller/ApiBillController.php @@ -24,6 +24,7 @@ use Modules\Billing\Models\BillElementMapper; use Modules\Billing\Models\BillMapper; use Modules\Billing\Models\BillStatus; use Modules\Billing\Models\BillTypeMapper; +use Modules\ClientManagement\Models\Client; use Modules\ClientManagement\Models\ClientMapper; use Modules\ItemManagement\Models\ItemMapper; use Modules\Media\Models\CollectionMapper; @@ -35,6 +36,8 @@ use Modules\SupplierManagement\Models\NullSupplier; use Modules\SupplierManagement\Models\SupplierMapper; use phpOMS\Autoloader; use phpOMS\Localization\ISO3166TwoEnum; +use phpOMS\Localization\ISO4217CharEnum; +use phpOMS\Localization\ISO639x1Enum; use phpOMS\Localization\Money; use phpOMS\Message\Http\RequestStatusCode; use phpOMS\Message\NotificationLevel; @@ -144,14 +147,59 @@ final class ApiBillController extends Controller return; } + // @todo: validate vat before creation $bill = $this->createBillFromRequest($request, $response, $data); + $this->createBillDatabaseEntry($bill, $request); + + $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Bill', 'Bill successfully created.', $bill); + } + + public function createBillDatabaseEntry(Bill $bill, RequestAbstract $request) : void + { $this->createModel($request->header->account, $bill, BillMapper::class, 'bill', $request->getOrigin()); $new = clone $bill; $new->buildNumber(); // The bill id is part of the number $this->updateModel($request->header->account, $bill, $new, BillMapper::class, 'bill', $request->getOrigin()); + } - $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Bill', 'Bill successfully created.', $bill); + public function createBaseBill(Client $client, RequestAbstract $request) : Bill + { + // @todo: validate vat before creation + $bill = new Bill(); + $bill->setStatus(BillStatus::DRAFT); + $bill->createdBy = new NullAccount($request->header->account); + $bill->billDate = new \DateTime('now'); // @todo: Date of payment + $bill->performanceDate = new \DateTime('now'); // @todo: Date of payment + + $bill->shipping = 0; + $bill->shippingText = ''; + + $bill->payment = 0; + $bill->paymentText = ''; + + // @todo: use bill and shipping address instead of main address if available + $bill->client = $client; + $bill->billTo = $client->account->name1; + $bill->billAddress = $client->mainAddress->address; + $bill->billCity = $client->mainAddress->city; + $bill->billZip = $client->mainAddress->postal; + $bill->billCountry = $client->mainAddress->getCountry(); + + $bill->setCurrency(ISO4217CharEnum::_EUR); + + // @todo implement allowed invoice languages and a default invoice language if none match + // @todo implement client invoice langage (this would allow invoice langauges which are different from the invoice address) + $bill->setLanguage( + !\in_array( + $client->mainAddress->getCountry(), + [ISO3166TwoEnum::_DEU, ISO3166TwoEnum::_AUT] + ) + ? ISO639x1Enum::_EN + : ISO639x1Enum::_DE + ); + + return $bill; } /** diff --git a/Controller/ApiPriceController.php b/Controller/ApiPriceController.php index 781daa7..8f6c32d 100755 --- a/Controller/ApiPriceController.php +++ b/Controller/ApiPriceController.php @@ -87,6 +87,7 @@ final class ApiPriceController extends Controller if ($request->hasData('price_client')) { /** @var null|\Modules\ClientManagement\Models\Client $client */ $client = ClientMapper::get() + ->with('attributes') ->with('attributes/type') ->with('attributes/value') ->where('id', (int) $request->getData('price_client')) @@ -97,6 +98,7 @@ final class ApiPriceController extends Controller } else { /** @var null|\Modules\SupplierManagement\Models\Supplier $supplier */ $supplier = SupplierMapper::get() + ->with('attributes') ->with('attributes/type') ->with('attributes/value') ->where('id', (int) $request->getData('price_supplier')) diff --git a/Models/Bill.php b/Models/Bill.php index fb86744..c648fd2 100755 --- a/Models/Bill.php +++ b/Models/Bill.php @@ -19,6 +19,7 @@ use Modules\Admin\Models\NullAccount; use Modules\Billing\Models\Attribute\BillAttribute; use Modules\ClientManagement\Models\Client; use Modules\Editor\Models\EditorDoc; +use Modules\ItemManagement\Models\Item; use Modules\Media\Models\Collection; use Modules\Media\Models\Media; use Modules\Media\Models\NullMedia; @@ -729,6 +730,17 @@ class Bill implements \JsonSerializable public function addElement(BillElement $element) : void { $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()); + + // @todo: Discount might be in quantities + $this->grossDiscount->add((int) ($element->taxR * $element->totalDiscountP->getInt() / 1000)); } /** diff --git a/Models/BillElement.php b/Models/BillElement.php index 52e7ac6..7f4cbb2 100755 --- a/Models/BillElement.php +++ b/Models/BillElement.php @@ -14,6 +14,8 @@ declare(strict_types=1); namespace Modules\Billing\Models; +use Modules\Finance\Models\TaxCode; +use Modules\ItemManagement\Models\Item; use phpOMS\Localization\Money; use phpOMS\Stdlib\Base\FloatInt; @@ -87,10 +89,24 @@ class BillElement implements \JsonSerializable public Money $totalProfitGross; + /** + * Tax amount + * + * @var null|FloatInt + * @since 1.0.0 + */ public ?FloatInt $taxP = null; + /** + * Tax percentage + * + * @var null|FloatInt + * @since 1.0.0 + */ public ?FloatInt $taxR = null; + public string $taxCode = ''; + /** * Event assigned to this element. * @@ -167,6 +183,44 @@ class BillElement implements \JsonSerializable $this->item = $item; } + public static function fromItem(Item $item, TaxCode $code) : self + { + $element = new self(); + $element->item = $item->getId(); + $element->itemNumber = $item->number; + $element->itemName = $item->getL11n('name1')->description; + $element->itemDescription = $item->getL11n('description_short')->description; + $element->quantity = 0; + + // @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->singleProfitNet->setInt($element->singleSalesPriceNet->getInt() - $element->singlePurchasePriceNet->getInt()); + $element->totalProfitNet->setInt($element->quantity * ($element->totalSalesPriceNet->getInt() - $element->totalPurchasePriceNet->getInt())); + + $element->taxP = new FloatInt((int) (($code->percentageInvoice * $element->totalSalesPriceNet->getInt()) / 1000)); + $element->taxR = new FloatInt($code->percentageInvoice); + $element->taxCode = $code->abbr; + + $element->singleListPriceGross->setInt((int) ($element->singleListPriceNet->getInt() + $element->singleListPriceNet->getInt() * $element->taxR->getInt() / 1000)); + $element->totalListPriceGross->setInt((int) ($element->totalListPriceNet->getInt() + $element->totalListPriceNet->getInt() * $element->taxR->getInt() / 1000)); + $element->singleSalesPriceGross->setInt((int) ($element->singleSalesPriceNet->getInt() + $element->singleSalesPriceNet->getInt() * $element->taxR->getInt() / 1000)); + $element->totalSalesPriceGross->setInt((int) ($element->totalSalesPriceNet->getInt() + $element->totalSalesPriceNet->getInt() * $element->taxR->getInt() / 1000)); + $element->singlePurchasePriceGross->setInt((int) ($element->singlePurchasePriceNet->getInt() + $element->singlePurchasePriceNet->getInt() * $element->taxR->getInt() / 1000)); + $element->totalPurchasePriceGross->setInt((int) ($element->totalPurchasePriceNet->getInt() + $element->totalPurchasePriceNet->getInt() * $element->taxR->getInt() / 1000)); + + $element->singleProfitGross->setInt($element->singleSalesPriceGross->getInt() - $element->singlePurchasePriceGross->getInt()); + $element->totalProfitGross->setInt($element->quantity * ($element->totalSalesPriceGross->getInt() - $element->totalPurchasePriceGross->getInt())); + + return $element; + } + /** * {@inheritdoc} */ diff --git a/Models/BillElementMapper.php b/Models/BillElementMapper.php index aed3691..6e3ab4f 100755 --- a/Models/BillElementMapper.php +++ b/Models/BillElementMapper.php @@ -61,6 +61,10 @@ final class BillElementMapper extends DataMapperFactory 'billing_bill_element_total_netpurchaseprice' => ['name' => 'billing_bill_element_total_netpurchaseprice', 'type' => 'Serializable', 'internal' => 'totalPurchasePriceNet'], 'billing_bill_element_total_grosspurchaseprice' => ['name' => 'billing_bill_element_total_grosspurchaseprice', 'type' => 'Serializable', 'internal' => 'totalPurchasePriceGross'], 'billing_bill_element_bill' => ['name' => 'billing_bill_element_bill', 'type' => 'int', 'internal' => 'bill'], + + 'billing_bill_element_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'], ]; /**