diff --git a/Admin/Install/Media.install.json b/Admin/Install/Media.install.json index 0903c3b..72d20cb 100755 --- a/Admin/Install/Media.install.json +++ b/Admin/Install/Media.install.json @@ -21,15 +21,17 @@ "user": 1 }, { - "type": "upload", - "create_collection": true, - "name": "Default", - "virtualPath": "/Modules/Billing/Templates", - "path": "/Modules/Media/Files/Modules/Billing/Templates/Default", - "fixed_names": true, - "files": [ - "/Modules/Billing/Admin/Install/Media" - ], - "user": 1 + "type": "type", + "name": "preview", + "l11n": [ + { + "title": "Preview", + "lang": "en" + }, + { + "title": "Vorschau", + "lang": "de" + } + ] } ] \ No newline at end of file diff --git a/Admin/Install/Media.php b/Admin/Install/Media.php index e4b6e35..b30adc1 100755 --- a/Admin/Install/Media.php +++ b/Admin/Install/Media.php @@ -43,9 +43,18 @@ class Media { $media = \Modules\Media\Admin\Installer::installExternal($app, ['path' => __DIR__ . '/Media.install.json']); - $defaultTemplate = \reset($media['upload'][0]); + $preivewType = (int) \reset($media['type'][0]); $setting = new Setting(); - SettingMapper::create()->execute($setting->with(0, SettingsEnum::DEFAULT_SALES_INVOICE_TEMPLATE, (string) $defaultTemplate->getId(), '\\d+', null, 'Billing')); + SettingMapper::create()->execute( + $setting->with( + 0, + SettingsEnum::PREVIEW_MEDIA_TYPE, + (string) $preivewType, + '\\d+', + null, + 'Billing' + ) + ); } } diff --git a/Admin/Install/Media2.install.json b/Admin/Install/Media2.install.json new file mode 100644 index 0000000..895180f --- /dev/null +++ b/Admin/Install/Media2.install.json @@ -0,0 +1,14 @@ +[ + { + "type": "upload", + "create_collection": true, + "name": "Default", + "virtualPath": "/Modules/Billing/Templates", + "path": "/Modules/Media/Files/Modules/Billing/Templates/Default", + "fixed_names": true, + "files": [ + "/Modules/Billing/Admin/Install/Media" + ], + "user": 1 + } +] \ No newline at end of file diff --git a/Admin/Install/db.json b/Admin/Install/db.json index 5d5aa95..bb0593a 100755 --- a/Admin/Install/db.json +++ b/Admin/Install/db.json @@ -9,6 +9,18 @@ "primary": true, "autoincrement": true }, + "billing_type_number_format": { + "name": "billing_type_number_format", + "type": "VARCHAR(254)", + "null": false + }, + "billing_type_template": { + "name": "billing_type_template", + "type": "INT", + "null": false, + "foreignTable": "media", + "foreignKey": "media_id" + }, "billing_type_transfer_type": { "description": "What kind of bill is it?", "name": "billing_type_transfer_type", diff --git a/Admin/Installer.php b/Admin/Installer.php index d2b26e6..28359cc 100755 --- a/Admin/Installer.php +++ b/Admin/Installer.php @@ -19,6 +19,8 @@ use Modules\Billing\Models\BillType; use Modules\Billing\Models\BillTypeL11n; use Modules\Billing\Models\BillTypeL11nMapper; use Modules\Billing\Models\BillTypeMapper; +use Modules\Media\Models\NullCollection; +use phpOMS\Application\ApplicationAbstract; use phpOMS\Config\SettingsInterface; use phpOMS\DataStorage\Database\DatabasePool; use phpOMS\Localization\ISO639x1Enum; @@ -50,9 +52,18 @@ final class Installer extends InstallerAbstract { parent::install($dbPool, $info, $cfgHandler); - self::createOutgoingBillTypes(); - self::createIncomingBillTypes(); - self::createTransferBillTypes(); + // Install bill type templates + $app = new class() extends ApplicationAbstract {}; + $app->dbPool = $dbPool; + + $media = \Modules\Media\Admin\Installer::installExternal($app, ['path' => __DIR__ . '/Install/Media2.install.json']); + + /** @var int $defaultTemplate */ + $defaultTemplate = (int) \reset($media['upload'][0])->getId(); + + self::createOutgoingBillTypes($defaultTemplate); + self::createIncomingBillTypes($defaultTemplate); + self::createTransferBillTypes($defaultTemplate); } /** @@ -62,45 +73,56 @@ final class Installer extends InstallerAbstract * * @since 1.0.0 */ - private static function createOutgoingBillTypes() : array + private static function createOutgoingBillTypes(int $template) : array { $billType = []; - // @todo: assign bill template here and not in the settings!!! // @todo: allow multiple alternative bill templates // @todo: implement ordering of templates $billType['offer'] = new BillType('Offer'); + $billType['offer']->numberFormat = '{y}-{id}'; + $billType['offer']->template = new NullCollection($template); $billType['offer']->transferType = BillTransferType::SALES; $billType['offer']->transferStock = false; BillTypeMapper::create()->execute($billType['offer']); BillTypeL11nMapper::create()->execute(new BillTypeL11n($billType['offer']->getId(), 'Angebot', ISO639x1Enum::_DE)); $billType['order_confirmation'] = new BillType('Order Confirmation'); + $billType['order_confirmation']->numberFormat = '{y}-{id}'; + $billType['order_confirmation']->template = new NullCollection($template); $billType['order_confirmation']->transferType = BillTransferType::SALES; $billType['order_confirmation']->transferStock = false; BillTypeMapper::create()->execute($billType['order_confirmation']); BillTypeL11nMapper::create()->execute(new BillTypeL11n($billType['order_confirmation']->getId(), 'Auftragsbestaetigung', ISO639x1Enum::_DE)); $billType['delivery_note'] = new BillType('Delivery Note'); + $billType['delivery_note']->numberFormat = '{y}-{id}'; + $billType['delivery_note']->template = new NullCollection($template); $billType['delivery_note']->transferType = BillTransferType::SALES; $billType['delivery_note']->transferStock = true; BillTypeMapper::create()->execute($billType['delivery_note']); BillTypeL11nMapper::create()->execute(new BillTypeL11n($billType['delivery_note']->getId(), 'Lieferschein', ISO639x1Enum::_DE)); $billType['invoice'] = new BillType('Invoice'); + $billType['invoice']->numberFormat = '{y}-{id}'; + $billType['invoice']->template = new NullCollection($template); $billType['invoice']->transferType = BillTransferType::SALES; $billType['invoice']->transferStock = false; BillTypeMapper::create()->execute($billType['invoice']); BillTypeL11nMapper::create()->execute(new BillTypeL11n($billType['invoice']->getId(), 'Rechnung', ISO639x1Enum::_DE)); $billType['credit_note'] = new BillType('Credit Note'); + $billType['credit_note']->numberFormat = '{y}-{id}'; + $billType['credit_note']->template = new NullCollection($template); $billType['credit_note']->transferType = BillTransferType::SALES; $billType['credit_note']->transferStock = false; BillTypeMapper::create()->execute($billType['credit_note']); BillTypeL11nMapper::create()->execute(new BillTypeL11n($billType['credit_note']->getId(), 'Rechnungskorrektur', ISO639x1Enum::_DE)); $billType['reverse_invoice'] = new BillType('Credit Note'); + $billType['reverse_invoice']->numberFormat = '{y}-{id}'; + $billType['reverse_invoice']->template = new NullCollection($template); $billType['reverse_invoice']->transferType = BillTransferType::SALES; $billType['reverse_invoice']->transferStock = false; BillTypeMapper::create()->execute($billType['reverse_invoice']); @@ -116,41 +138,53 @@ final class Installer extends InstallerAbstract * * @since 1.0.0 */ - private static function createIncomingBillTypes() : array + private static function createIncomingBillTypes(int $template) : array { $billType = []; $billType['offer'] = new BillType('Offer'); + $billType['offer']->numberFormat = '{y}-{id}'; + $billType['offer']->template = new NullCollection($template); $billType['offer']->transferType = BillTransferType::PURCHASE; $billType['offer']->transferStock = false; BillTypeMapper::create()->execute($billType['offer']); BillTypeL11nMapper::create()->execute(new BillTypeL11n($billType['offer']->getId(), 'Angebot', ISO639x1Enum::_DE)); $billType['order_confirmation'] = new BillType('Order Confirmation'); + $billType['order_confirmation']->numberFormat = '{y}-{id}'; + $billType['order_confirmation']->template = new NullCollection($template); $billType['order_confirmation']->transferType = BillTransferType::PURCHASE; $billType['order_confirmation']->transferStock = false; BillTypeMapper::create()->execute($billType['order_confirmation']); BillTypeL11nMapper::create()->execute(new BillTypeL11n($billType['order_confirmation']->getId(), 'Auftragsbestaetigung', ISO639x1Enum::_DE)); $billType['delivery_note'] = new BillType('Delivery Note'); + $billType['delivery_note']->numberFormat = '{y}-{id}'; + $billType['delivery_note']->template = new NullCollection($template); $billType['delivery_note']->transferType = BillTransferType::PURCHASE; $billType['delivery_note']->transferStock = true; BillTypeMapper::create()->execute($billType['delivery_note']); BillTypeL11nMapper::create()->execute(new BillTypeL11n($billType['delivery_note']->getId(), 'Lieferschein', ISO639x1Enum::_DE)); $billType['invoice'] = new BillType('Invoice'); + $billType['invoice']->numberFormat = '{y}-{id}'; + $billType['invoice']->template = new NullCollection($template); $billType['invoice']->transferType = BillTransferType::PURCHASE; $billType['invoice']->transferStock = false; BillTypeMapper::create()->execute($billType['invoice']); BillTypeL11nMapper::create()->execute(new BillTypeL11n($billType['invoice']->getId(), 'Rechnung', ISO639x1Enum::_DE)); $billType['credit_note'] = new BillType('Credit Note'); + $billType['credit_note']->numberFormat = '{y}-{id}'; + $billType['credit_note']->template = new NullCollection($template); $billType['credit_note']->transferType = BillTransferType::PURCHASE; $billType['credit_note']->transferStock = false; BillTypeMapper::create()->execute($billType['credit_note']); BillTypeL11nMapper::create()->execute(new BillTypeL11n($billType['credit_note']->getId(), 'Rechnungskorrektur', ISO639x1Enum::_DE)); $billType['reverse_invoice'] = new BillType('Credit Note'); + $billType['reverse_invoice']->numberFormat = '{y}-{id}'; + $billType['reverse_invoice']->template = new NullCollection($template); $billType['reverse_invoice']->transferType = BillTransferType::PURCHASE; $billType['reverse_invoice']->transferStock = false; BillTypeMapper::create()->execute($billType['reverse_invoice']); @@ -166,7 +200,7 @@ final class Installer extends InstallerAbstract * * @since 1.0.0 */ - private static function createTransferBillTypes() : array + private static function createTransferBillTypes(int $template) : array { return []; } diff --git a/Controller/ApiController.php b/Controller/ApiController.php index 6e4f269..9c4c330 100755 --- a/Controller/ApiController.php +++ b/Controller/ApiController.php @@ -19,11 +19,10 @@ use Modules\Billing\Models\Bill; use Modules\Billing\Models\BillElement; use Modules\Billing\Models\BillElementMapper; use Modules\Billing\Models\BillMapper; -use Modules\Billing\Models\NullBillType; +use Modules\Billing\Models\BillTypeMapper; use Modules\Billing\Models\SettingsEnum; use Modules\ClientManagement\Models\ClientMapper; use Modules\ItemManagement\Models\ItemMapper; -use Modules\Media\Models\CollectionMapper; use Modules\Media\Models\UploadStatus; use Modules\SupplierManagement\Models\SupplierMapper; use phpOMS\Autoloader; @@ -107,17 +106,20 @@ final class ApiController extends Controller ->execute(); } + /** @var \Modules\Billing\Models\BillType $billType */ + $billType = BillTypeMapper::get()->where('id', (int) ($request->getData('type') ?? 1))->execute(); + /* @var \Modules\Account\Models\Account $account */ $bill = new Bill(); $bill->createdBy = new NullAccount($request->header->account); - $bill->numberFormat = '{y}-{id}'; // @todo: use admin defined format + $bill->type = $billType; + $bill->numberFormat = $billType->numberFormat; $bill->billTo = $request->getData('billto') ?? ($account->profile->account->name1 . (!empty($account->profile->account->name2) ? ', ' . $account->profile->account->name2 : '')); // @todo: use defaultInvoiceAddress or mainAddress. also consider to use billto1, billto2, billto3 (for multiple lines e.g. name2, fao etc.) $bill->billAddress = $request->getData('billaddress') ?? $account->mainAddress->address; $bill->billZip = $request->getData('billtopostal') ?? $account->mainAddress->postal; $bill->billCity = $request->getData('billtocity') ?? $account->mainAddress->city; $bill->billCountry = $request->getData('billtocountry') ?? $account->mainAddress->getCountry(); - $bill->type = new NullBillType((int) $request->getData('type')); $bill->client = $request->getData('client') === null ? null : $account; $bill->supplier = $request->getData('supplier') === null ? null : $account; $bill->performanceDate = new \DateTime($request->getData('performancedate') ?? 'now'); @@ -360,14 +362,19 @@ final class ApiController extends Controller { Autoloader::addPath(__DIR__ . '/../../../Resources/'); - $bill = BillMapper::get()->where('id', $request->getData('bill'))->execute(); + $bill = BillMapper::get() + ->with('type') + ->with('type/template') + ->with('type/template/sources') + ->where('id', $request->getData('bill') ?? 0) + ->execute(); - // @todo: change once bill types have media files/templates assigned - $defaultTemplate = $this->app->appSettings->get( - names: SettingsEnum::DEFAULT_SALES_INVOICE_TEMPLATE, + $previewType = (int) $this->app->appSettings->get( + names: SettingsEnum::PREVIEW_MEDIA_TYPE, module: self::NAME - ); - $template = CollectionMapper::get()->where('id', (int) $defaultTemplate->content)->execute(); + )->content; + + $template = $bill->type->template; $pdfDir = __DIR__ . '/../../../Modules/Media/Files/Modules/Billing/Bills/' . $bill->createdAt->format('Y') . '/' @@ -411,7 +418,7 @@ final class ApiController extends Controller . $bill->createdAt->format('Y') . '/' . $bill->createdAt->format('m') . '/' . $bill->createdAt->format('d'), - null // @todo: get bill MediaType + $previewType ); $this->createModelRelation( diff --git a/Controller/BackendController.php b/Controller/BackendController.php index f0e6a9d..391dc75 100755 --- a/Controller/BackendController.php +++ b/Controller/BackendController.php @@ -16,6 +16,7 @@ namespace Modules\Billing\Controller; use Modules\Billing\Models\PurchaseBillMapper; use Modules\Billing\Models\SalesBillMapper; +use Modules\Billing\Models\SettingsEnum; use Modules\Billing\Models\StockBillMapper; use phpOMS\Asset\AssetType; use phpOMS\Contract\RenderableInterface; @@ -107,10 +108,22 @@ final class BackendController extends Controller $view->setTemplate('/Modules/Billing/Theme/Backend/sales-bill'); $view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1005104001, $request, $response)); - $bill = SalesBillMapper::get()->with('elements')->where('id', (int) $request->getData('id'))->execute(); + $bill = SalesBillMapper::get() + ->with('elements') + ->with('media') + ->with('notes') + ->where('id', (int) $request->getData('id')) + ->execute(); $view->setData('bill', $bill); + $previewType = (int) $this->app->appSettings->get( + names: SettingsEnum::PREVIEW_MEDIA_TYPE, + module: self::NAME + )->content; + + $view->setData('previewType', $previewType); + return $view; } @@ -234,6 +247,13 @@ final class BackendController extends Controller $view->setData('bill', $bill); + $previewType = (int) $this->app->appSettings->get( + names: SettingsEnum::PREVIEW_MEDIA_TYPE, + module: self::NAME + )->content; + + $view->setData('previewType', $previewType); + return $view; } diff --git a/Models/Bill.php b/Models/Bill.php index 86f7d64..1d2e5c0 100755 --- a/Models/Bill.php +++ b/Models/Bill.php @@ -707,7 +707,7 @@ class Bill implements \JsonSerializable { $files = []; foreach ($this->media as $file) { - if ($file->type === $type) { + if ($file->type->getId() === $type) { $files[] = $file; } } @@ -726,9 +726,8 @@ class Bill implements \JsonSerializable */ public function getFileByType(int $type = null) : Media { - $files = []; foreach ($this->media as $file) { - if ($file->type === $type) { + if ($file->type->getId() === $type) { return $file; } } @@ -742,22 +741,22 @@ class Bill implements \JsonSerializable public function toArray() : array { return [ - 'id' => $this->id, - 'number' => $this->number, - 'numberFormat' => $this->numberFormat, - '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, + 'numberFormat' => $this->numberFormat, + '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, ]; } diff --git a/Models/BillType.php b/Models/BillType.php index f9cc24e..e24059c 100755 --- a/Models/BillType.php +++ b/Models/BillType.php @@ -14,6 +14,8 @@ declare(strict_types=1); namespace Modules\Billing\Models; +use Modules\Media\Models\Collection; +use Modules\Media\Models\NullCollection; use phpOMS\Localization\ISO639x1Enum; /** @@ -34,6 +36,10 @@ class BillType */ protected int $id = 0; + public Collection $template; + + public string $numberFormat = ''; + public int $transferType = BillTransferType::SALES; public bool $transferStock = true; @@ -54,6 +60,7 @@ class BillType */ public function __construct(string $name = '') { + $this->media = new NullCollection(); $this->setL11n($name); } diff --git a/Models/BillTypeMapper.php b/Models/BillTypeMapper.php index 810e372..71ad928 100755 --- a/Models/BillTypeMapper.php +++ b/Models/BillTypeMapper.php @@ -14,6 +14,7 @@ declare(strict_types=1); namespace Modules\Billing\Models; +use Modules\Media\Models\CollectionMapper; use phpOMS\DataStorage\Database\Mapper\DataMapperFactory; /** @@ -33,9 +34,24 @@ 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_transfer_type' => ['name' => 'billing_type_transfer_type', 'type' => 'int', 'internal' => 'transferType'], - 'billing_type_transfer_stock' => ['name' => 'billing_type_transfer_stock', 'type' => 'bool', 'internal' => 'transferStock'], + 'billing_type_id' => ['name' => 'billing_type_id', 'type' => 'int', 'internal' => 'id'], + 'billing_type_number_format' => ['name' => 'billing_type_number_format', 'type' => 'string', 'internal' => 'numberFormat'], + 'billing_type_template' => ['name' => 'billing_type_template', 'type' => 'int', 'internal' => 'template'], + 'billing_type_transfer_type' => ['name' => 'billing_type_transfer_type', 'type' => 'int', 'internal' => 'transferType'], + 'billing_type_transfer_stock' => ['name' => 'billing_type_transfer_stock', 'type' => 'bool', 'internal' => 'transferStock'], + ]; + + /** + * Belongs to. + * + * @var array + * @since 1.0.0 + */ + public const OWNS_ONE = [ + 'template' => [ + 'mapper' => CollectionMapper::class, + 'external' => 'billing_type_template', + ], ]; /** diff --git a/Models/SettingsEnum.php b/Models/SettingsEnum.php index 125b0ea..fa8c15c 100644 --- a/Models/SettingsEnum.php +++ b/Models/SettingsEnum.php @@ -26,5 +26,5 @@ use phpOMS\Stdlib\Base\Enum; */ abstract class SettingsEnum extends Enum { - public const DEFAULT_SALES_INVOICE_TEMPLATE = '1005100001_1'; + public const PREVIEW_MEDIA_TYPE = '1005100001_1'; } diff --git a/Theme/Backend/sales-bill.tpl.php b/Theme/Backend/sales-bill.tpl.php index 27020de..a0a0358 100755 --- a/Theme/Backend/sales-bill.tpl.php +++ b/Theme/Backend/sales-bill.tpl.php @@ -12,16 +12,22 @@ */ declare(strict_types=1); +use phpOMS\System\File\FileUtils; use phpOMS\Uri\UriFactory; +// Media helper functions (e.g. file icon generator) +include __DIR__ . '/../../../Media/Theme/Backend/template-functions.php'; + /** * @var \phpOMS\Views\View $this */ /** @var Modules\Billing\Models\Bill $bill */ $bill = $this->getData('bill'); $elements = $bill->getElements(); +$media = $bill->getMedia(); -$billPdf = $bill->getFileByType(0); +$previewType = $this->getData('previewType'); +$billPdf = $bill->getFileByType($previewType); echo $this->getData('nav')->render(); ?> @@ -258,6 +264,40 @@ echo $this->getData('nav')->render(); ?> + +
+
+
getHtml('Media'); ?>
+ + + + + extension === 'collection' + ? UriFactory::build('{/prefix}media/list?path=' . \rtrim($file->getVirtualPath(), '/') . '/' . $file->name) + : UriFactory::build('{/prefix}media/single?id=' . $file->getId() + . '&path={?path}' . ( + $file->getId() === 0 + ? '/' . $file->name + : '' + ) + ); + + $icon = $fileIconFunction(FileUtils::getExtensionType($file->extension)); + ?> + +
+ + getHtml('Name'); ?> + getHtml('Type'); ?> +
+ + name; ?> + extension; ?> + +
+
+