continue implementations

This commit is contained in:
Dennis Eichhorn 2024-01-12 00:30:03 +00:00
parent 655d816bf8
commit cf138cd266
39 changed files with 1005 additions and 508 deletions

View File

@ -1,370 +0,0 @@
[
{
"name": "1",
"l11n": {
"en": "Turnover",
"de": "Umsatzerlöse"
},
"account": [2750,2751,2752,2753,2754,2764],
"type": "category",
"formula": "",
"style": "category",
"children": []
},
{
"name": "2",
"l11n": {
"en": "Increase or reduction of stocks of finished goods and work in progress",
"de": "Erhöhung oder Verminderung des Bestands an fertigen und unfertigen Erzeugnissen"
},
"account": [],
"type": "category",
"formula": "",
"style": "category",
"children": []
},
{
"name": "3",
"l11n": {
"en": "Work performed by the undertaking for its own purposes and carried as an asset",
"de": "Andere aktivierte Eigenleistungen"
},
"account": [],
"type": "category",
"formula": "",
"style": "category",
"children": []
},
{
"name": "4",
"l11n": {
"en": "Other operating earnings",
"de": "Sonstige betriebliche Erträge"
},
"account": [2315,2316,2317,2318,2500,2501,2504,2508,2510,2520,2590,2594,2660,2661,2666,2700,2705,2707,2709,2710,2711,2712,2713,2714,2715,2716,2720,2723,2725,2726,2727,2728,2729,2730,2731,2732,2735,2736,2737,2740,2741,2742,2743,2744,2746,2747,2749,2760,2762,2790,2745,2746,2747,2749],
"type": "category",
"formula": "",
"style": "category",
"children": []
},
{
"name": "5",
"l11n": {
"en": "Expenditures on materials",
"de": "Materialaufwand"
},
"account": [],
"type": "category",
"formula": "",
"style": "category",
"children": [
{
"name": "5a",
"l11n": {
"en": "Expenditures for raw materials, auxiliary supplies and consumables and for purchased goods",
"de": "Aufwendungen für Roh-, Hilfs- und Betriebsstoffe und für bezogene Waren"
},
"account": [3000,3010,3011,3012,3013,3014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3024,3025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039,3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,3051,3052,3053,3054,3055,3056,3057,3058,3059,3060,3061,3062,3063,3064,3065,3066,3067,3068,3069,3070,3071,3072,3073,3074,3075,3076,3077,3078,3079,3080,3081,3082,3083,3084,3085,3086,3087,3088,3089,3090,3091,3092,3093,3094,3095,3096,3097,3098,3200,3300,3301,3302,3303,3304,3305,3306,3307,3308,3309,3310,3311,3312,3313,3314,3315,3316,3317,3318,3319,3320,3321,3322,3323,3324,3325,3326,3327,3328,3329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339,3340,3341,3342,3343,3344,3345,3346,3347,3348,3349,3400,3401,3402,3403,3404,3405,3406,3407,3408,3409,3410,3411,3412,3413,3414,3415,3416,3417,3418,3419,3420,3421,3422,3423,3424,3425,3426,3427,3428,3429,3430,3431,3432,3433,3434,3435],
"type": "category",
"formula": "",
"style": "category",
"children": []
},
{
"name": "5b",
"l11n": {
"en": "Expenditures for purchased services",
"de": "Aufwendungen für bezogene Leistungen"
},
"account": [3100,3106,3107,3108,3109,3110,3111,3112,3113,3114,3115,3116,3117,3118,3119,3120,3121,3122,3123,3124,3125,3126,3127,3128,3129,3130,3131,3132,3133,3134,3135,3136,3137,3138,3139,3140,3141,3142,3143,3144,3145,3146,3147,3148,3149,3150,3151,3152,3153,3154,3155,3156,3157,3158,3159,3160,3165,3170,3175,3180,3185],
"type": "category",
"formula": "",
"style": "category",
"children": []
}
]
},
{
"name": "GP",
"l11n": {
"en": "Gross profit",
"de": "Rohertrag"
},
"account": [],
"type": "formula",
"formula": "1+2+3+4+5",
"style": "subtotal",
"children": []
},
{
"name": "GPratio",
"l11n": {
"en": "Gross profit ratio",
"de": "Rohertragsmarge"
},
"account": [],
"type": "formula",
"formula": "GP/(1+2+3+4)",
"style": "ratio",
"children": []
},
{
"name": "6",
"l11n": {
"en": "Staff costs",
"de": "Personalaufwand"
},
"account": [],
"type": "category",
"formula": "",
"style": "category",
"children": [
{
"name": "6a",
"l11n": {
"en": "Wages and salaries",
"de": "Löhne und Gehälter"
},
"account": [],
"type": "category",
"formula": "",
"style": "category",
"children": []
},
{
"name": "6b",
"l11n": {
"en": "Social security contributions and expenditures for old-age pension schemes and for support",
"de": "soziale Abgaben und Aufwendungen für Altersversorgung und für Unterstützung"
},
"account": [],
"type": "category",
"formula": "",
"style": "category",
"children": [
{
"name": "6bthereof",
"l11n": {
"en": "thereof relating to the old-age pension scheme",
"de": "davon für Altersversorgung"
},
"account": [],
"type": "category",
"formula": "",
"style": "category",
"children": []
}
]
}
]
},
{
"name": "7",
"l11n": {
"en": "Amortisations / depreciations",
"de": "Abschreibungen"
},
"account": [],
"type": "category",
"formula": "",
"style": "category",
"children": [
{
"name": "7a",
"l11n": {
"en": "Intangible assets forming part of the fixed assets and of tangible fixed assets",
"de": "auf immaterielle Vermögensgegenstände des Anlagevermögens und Sachanlage"
},
"account": [],
"type": "category",
"formula": "",
"style": "category",
"children": []
},
{
"name": "7b",
"l11n": {
"en": "Assets reported as part of the current assets, to the extent that they exceed the depreciations customarily stated for the share capital company",
"de": "auf Vermögensgegenstände des Umlaufvermögens, soweit diese die in der Kapitalgesellschaft üblichen Abschreibungen überschreiten"
},
"account": [2430,2431,2432,2433,2434,2345,2436,2437,2438,2440,2441],
"type": "category",
"formula": "",
"style": "category",
"children": []
}
]
},
{
"name": "8",
"l11n": {
"en": "Other operating expenses",
"de": "Sonstige betriebliche Aufwendungen"
},
"account": [2150,2151,2166,2170,2171,2174,2175,2176,2300,2307,2308,2309,2310,2311,2312,2313,2320,2323,2325,2326,2327,2328,2339,2342,2343,2344,2345,2347,2350,2380,2381,2382,2383,2384,2385,2386,2387,2389,2390,2400,2401,2402,2403,2404,2405,2406,2407,2408,2409,2450,2451,2490,2890,2891,2892,2893,2894,2895,2900],
"type": "category",
"formula": "",
"style": "category",
"children": []
},
{
"name": "9",
"l11n": {
"en": "Income from participating interests",
"de": "Erträge aus Beteiligungen"
},
"account": [2480,2491,2492,2493,2494,2495,2496,2497,2498,2499,2600,2603,2613,2614,2615,2616,2618,2619,2792,2794],
"type": "category",
"formula": "",
"style": "category",
"children": [
{
"name": "9thereof",
"l11n": {
"en": "thereof derived from affiliated undertakings",
"de": "davon aus verbundenen Unternehmen"
},
"account": [],
"type": "category",
"formula": "",
"style": "category",
"children": []
}
]
},
{
"name": "10",
"l11n": {
"en": "Income from other investments and loans forming part of the financial assets",
"de": "Erträge aus anderen Wertpapieren und Ausleihungen des Finanzanlagevermögens"
},
"account": [2620,2621,2622,2623,2625,2626,2640,2641,2646,2647,2648,2649],
"type": "category",
"formula": "",
"style": "category",
"children": [
{
"name": "10thereof",
"l11n": {
"en": "thereof derived from affiliated undertakings",
"de": "davon aus verbundenen Unternehmen"
},
"account": [],
"type": "category",
"formula": "",
"style": "category",
"children": []
}
]
},
{
"name": "11",
"l11n": {
"en": "Other interest receivable and similar income",
"de": "Sonstige Zinsen und ähnliche Erträge"
},
"account": [2650,2653,2654,2655,2656,2657,2658,2659,2670,2679,2680,2682,2683,2684,2685,2686,2687,2688,2689],
"type": "category",
"formula": "",
"style": "category",
"children": [
{
"name": "11thereof",
"l11n": {
"en": "thereof derived from affiliated undertakings",
"de": "davon aus verbundenen Unternehmen"
},
"account": [],
"type": "category",
"formula": "",
"style": "category",
"children": []
}
]
},
{
"name": "12",
"l11n": {
"en": "Depreciations of financial assets and of investment securities forming part of the current assets",
"de": "Abschreibungen auf Finanzanlagen und auf Wertpapiere des Umlaufvermögens"
},
"account": [],
"type": "category",
"formula": "",
"style": "category",
"children": []
},
{
"name": "13",
"l11n": {
"en": "Interest payable and similar expenses",
"de": "Zinsen und ähnliche Aufwendungen,"
},
"account": [2105,2106,2107,2108,2109,2110,2111,2113,2114,2115,2116,2117,2118,2119,2120,2123,2124,2125,2126,2127,2128,2129,2130,2139,2140,2141,2142,2143,2144,2145,2146,2147,2148,2149],
"type": "category",
"formula": "",
"style": "category",
"children": [
{
"name": "13thereof",
"l11n": {
"en": "thereof derived from affiliated undertakings",
"de": "davon aus verbundenen Unternehmen"
},
"account": [],
"type": "category",
"formula": "",
"style": "category",
"children": []
}
]
},
{
"name": "14",
"l11n": {
"en": "Taxes on income and earnings",
"de": "Steuern vom Einkommen und vom Ertrag"
},
"account": [2200,2203,2204,2208,2209,2210,2213,2216,2218,2219,2250,2255,2260,2265,2281,2283],
"type": "category",
"formula": "",
"style": "category",
"children": []
},
{
"name": "15",
"l11n": {
"en": "Profit or loss after taxes",
"de": "Ergebnis nach Steuern"
},
"account": [],
"type": "formula",
"formula": "1+2+3+4+5+6+7+8+9+10+11+12+13+14",
"style": "subtotal",
"children": []
},
{
"name": "16",
"l11n": {
"en": "Other taxes",
"de": "Sonstige Steuern"
},
"account": [2285,2287,2289,2375],
"type": "category",
"formula": "",
"style": "category",
"children": []
},
{
"name": "17",
"l11n": {
"en": "Net income for the year / net loss for the year",
"de": "Jahresüberschuss/Jahresfehlbetrag"
},
"account": [],
"type": "formula",
"formula": "15+16",
"style": "total",
"children": []
}
]

View File

@ -9,10 +9,11 @@
"primary": true,
"autoincrement": true
},
"accounting_account_account": {
"name": "accounting_account_account",
"accounting_account_code": {
"name": "accounting_account_code",
"type": "VARCHAR(50)",
"null": false
"null": false,
"unique": true
},
"accounting_account_type": {
"name": "accounting_account_type",
@ -24,6 +25,14 @@
"type": "INT",
"default": null,
"null": true
},
"accounting_account_account": {
"name": "accounting_account_account",
"type": "INT",
"default": null,
"null": true,
"foreignTable": "account",
"foreignKey": "account_id"
}
}
},

View File

@ -14,6 +14,7 @@ declare(strict_types=1);
namespace Modules\Accounting\Admin;
use Modules\Accounting\Models\AccountType;
use phpOMS\Application\ApplicationAbstract;
use phpOMS\Config\SettingsInterface;
use phpOMS\Localization\ISO639x1Enum;
@ -65,7 +66,7 @@ final class Installer extends InstallerAbstract
/** @var \Modules\Accounting\Controller\ApiController $module */
$module = $app->moduleManager->getModuleInstance('Accounting', 'Api');
$fp = \fopen(__DIR__ . '/Install/Coa/skr03.csv', 'r');
$fp = \fopen(__DIR__ . '/Install/Coa/SKR03_DE_GAAP.csv', 'r');
if ($fp === false) {
return;
}
@ -90,7 +91,7 @@ final class Installer extends InstallerAbstract
$request = new HttpRequest(new HttpUri(''));
$request->header->account = 1;
$request->setData('account', $line[0]);
$request->setData('code', $line[0]);
$request->setData('content', \trim($line[19]));
$request->setData('language', $definitions[19]);
$module->apiAccountCreate($request, $response);
@ -140,7 +141,11 @@ final class Installer extends InstallerAbstract
? \Modules\ClientManagement\Models\ClientMapper::class
: \Modules\SupplierManagement\Models\SupplierMapper::class;
foreach ($mapper::yield() as $person) {
$accountType = $type === 'client'
? AccountType::DEBITOR
: AccountType::CREDITOR;
foreach ($mapper::yield()->execute() as $person) {
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
@ -148,9 +153,11 @@ final class Installer extends InstallerAbstract
// @todo define default account number format for suppliers, if number -> consider number as starting value
$request->header->account = 1;
$request->setData('account', $person->number);
$request->setData('code', $person->number);
$request->setData('content', \rtrim($person->account->name1 . ' ' . $person->account->name2));
$request->setData('language', ISO639x1Enum::_EN);
$request->setData('language', ISO639x1Enum::_EN); // @todo personal accounts shouldn't have a translation?!
$request->setData('type', $accountType);
$request->setData('account', $person->account->id);
$module->apiAccountCreate($request, $response);
}
}

View File

@ -18,28 +18,6 @@ use phpOMS\Account\PermissionType;
use phpOMS\Router\RouteVerb;
return [
'^.*/accounting/personal/entries.*$' => [
[
'dest' => '\Modules\Accounting\Controller\BackendController:viewPersonalEntries',
'verb' => RouteVerb::GET,
'permission' => [
'module' => BackendController::NAME,
'type' => PermissionType::READ,
'state' => PermissionCategory::PERSONAL,
],
],
],
'^.*/accounting/impersonal/entries.*$' => [
[
'dest' => '\Modules\Accounting\Controller\BackendController:viewImpersonalEntries',
'verb' => RouteVerb::GET,
'permission' => [
'module' => BackendController::NAME,
'type' => PermissionType::READ,
'state' => PermissionCategory::IMPERSONAL,
],
],
],
'^.*/accounting/entries.*$' => [
[
'dest' => '\Modules\Accounting\Controller\BackendController:viewEntries',
@ -51,17 +29,6 @@ return [
],
],
],
'^.*/accounting/impersonal/journal/list.*$' => [
[
'dest' => '\Modules\Accounting\Controller\BackendController:viewJournalList',
'verb' => RouteVerb::GET,
'permission' => [
'module' => BackendController::NAME,
'type' => PermissionType::READ,
'state' => PermissionCategory::JOURNAL,
],
],
],
'^.*/accounting/stack/list.*$' => [
[
'dest' => '\Modules\Accounting\Controller\BackendController:viewStackList',
@ -150,17 +117,6 @@ return [
],
],
],
'^.*/accounting/gl/profile.*$' => [
[
'dest' => '\Modules\Accounting\Controller\BackendController:viewGLProfile',
'verb' => RouteVerb::GET,
'permission' => [
'module' => BackendController::NAME,
'type' => PermissionType::READ,
'state' => PermissionCategory::GL,
],
],
],
'^.*/accounting/dun/print.*$' => [
[
'dest' => '\Modules\Accounting\Controller\BackendController:viewCostCenterProfile',

92
Controller.js Normal file
View File

@ -0,0 +1,92 @@
import { jsOMS } from '../../jsOMS/Utils/oLib.js';
import { Autoloader } from '../../jsOMS/Autoloader.js';
Autoloader.defineNamespace('omsApp.Modules');
omsApp.Modules.Accounting = class {
/**
* @constructor
*
* @since 1.0.0
*/
constructor (app)
{
this.app = app;
};
bind (id)
{
const charts = typeof id === 'undefined' ? document.getElementsByTagName('canvas') : [document.getElementById(id)];
let length = charts.length;
for (let i = 0; i < length; ++i) {
if (charts[i].getAttribute('data-chart') === null
&& charts[i].getAttribute('data-chart') !== 'undefined'
) {
continue;
}
this.bindChart(charts[i]);
}
const maps = typeof id === 'undefined' ? document.getElementsByClassName('map') : [document.getElementById(id)];
length = maps.length;
for (let i = 0; i < length; ++i) {
this.bindMap(maps[i]);
}
};
bindChart (chart)
{
if (typeof chart === 'undefined' || !chart) {
jsOMS.Log.Logger.instance.error('Invalid chart: ' + chart, 'Accounting');
return;
}
const self = this;
const data = JSON.parse(chart.getAttribute('data-chart'));
const myChart = new Chart(chart.getContext('2d'), data);
};
bindMap (map)
{
if (typeof map === 'undefined' || !map) {
jsOMS.Log.Logger.instance.error('Invalid map: ' + map, 'Accounting');
return;
}
const mapObj = new OpenLayers.Map(map.getAttribute('id'), {
controls: [
new OpenLayers.Control.Navigation(
{
zoomBoxEnabled: true,
zoomWheelEnabled: false
}
),
new OpenLayers.Control.Zoom(),
new OpenLayers.Control.Attribution()
]
});
mapObj.addLayer(new OpenLayers.Layer.OSM());
const fromProjection = new OpenLayers.Projection("EPSG:4326"); // Transform from WGS 1984
const toProjection = new OpenLayers.Projection("EPSG:900913"); // to Spherical Mercator Projection
const position = new OpenLayers.LonLat(map.getAttribute('data-lon'), map.getAttribute('data-lat')).transform(fromProjection, toProjection);
const zoom = 12;
const markers = new OpenLayers.Layer.Markers("Markers");
mapObj.addLayer(markers);
markers.addMarker(new OpenLayers.Marker(position));
mapObj.setCenter(position, zoom);
};
};
window.omsApp.moduleManager.get('Accounting').bind();

View File

@ -17,6 +17,7 @@ namespace Modules\Accounting\Controller;
use Modules\Accounting\Models\AccountAbstract;
use Modules\Accounting\Models\AccountAbstractMapper;
use Modules\Accounting\Models\AccountL11nMapper;
use Modules\Accounting\Models\AccountType;
use Modules\Accounting\Models\CostCenter;
use Modules\Accounting\Models\CostCenterMapper;
use Modules\Accounting\Models\CostObject;
@ -84,8 +85,7 @@ final class ApiController extends Controller
private function validateAccountCreate(RequestAbstract $request) : array
{
$val = [];
if (($val['account'] = !$request->hasData('account'))
|| ($val['content'] = !$request->hasData('content'))
if (($val['code'] = !$request->hasData('code'))
) {
return $val;
}
@ -105,8 +105,14 @@ final class ApiController extends Controller
private function createAccountFromRequest(RequestAbstract $request) : AccountAbstract
{
$account = new AccountAbstract();
$account->account = $request->getDataString('account') ?? '';
$account->setL11n($request->getDataString('content') ?? '', $request->getDataString('language') ?? ISO639x1Enum::_EN);
$account->code = $request->getDataString('code') ?? '';
$account->account = $request->getDataInt('account');
if ($request->hasData('content')) {
$account->setL11n($request->getDataString('content') ?? '', $request->getDataString('language') ?? ISO639x1Enum::_EN);
}
$account->type = $request->getDataInt('type') ?? AccountType::IMPERSONAL;
return $account;
}

View File

@ -17,11 +17,22 @@ namespace Modules\Accounting\Controller;
use Modules\Accounting\Models\AccountAbstractMapper;
use Modules\Accounting\Models\CostCenterMapper;
use Modules\Accounting\Models\CostObjectMapper;
use Modules\Admin\Models\LocalizationMapper;
use Modules\Admin\Models\SettingsEnum;
use Modules\Auditor\Models\AuditMapper;
use Modules\ClientManagement\Models\Attribute\ClientAttributeTypeMapper;
use Modules\ClientManagement\Models\ClientMapper;
use Modules\Media\Models\MediaMapper;
use Modules\Media\Models\MediaTypeMapper;
use Modules\Organization\Models\Attribute\UnitAttributeMapper;
use Modules\SupplierManagement\Models\SupplierMapper;
use phpOMS\Asset\AssetType;
use phpOMS\Contract\RenderableInterface;
use phpOMS\DataStorage\Database\Query\Builder;
use phpOMS\DataStorage\Database\Query\OrderType;
use phpOMS\Message\RequestAbstract;
use phpOMS\Message\ResponseAbstract;
use phpOMS\Utils\StringUtils;
use phpOMS\Views\View;
/**
@ -229,27 +240,6 @@ final class BackendController extends Controller
return $view;
}
/**
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return RenderableInterface
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function viewGLProfile(RequestAbstract $request, ResponseAbstract $response, array $data = []) : RenderableInterface
{
$view = new View($this->app->l11nManager, $request, $response);
$view->setTemplate('/Modules/Accounting/Theme/Backend/gl-profile');
$view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1002604001, $request, $response);
return $view;
}
/**
* Routing end-point for application behavior.
*
@ -265,7 +255,7 @@ final class BackendController extends Controller
public function viewCostCenterProfile(RequestAbstract $request, ResponseAbstract $response, array $data = []) : RenderableInterface
{
$view = new View($this->app->l11nManager, $request, $response);
$view->setTemplate('/Modules/Accounting/Theme/Backend/gl-profile');
$view->setTemplate('/Modules/Accounting/Theme/Backend/costcenter-profile');
$view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1002604001, $request, $response);
return $view;
@ -283,31 +273,10 @@ final class BackendController extends Controller
* @since 1.0.0
* @codeCoverageIgnore
*/
public function viewImpersonalEntries(RequestAbstract $request, ResponseAbstract $response, array $data = []) : RenderableInterface
public function viewCostObjectProfile(RequestAbstract $request, ResponseAbstract $response, array $data = []) : RenderableInterface
{
$view = new View($this->app->l11nManager, $request, $response);
$view->setTemplate('/Modules/Accounting/Theme/Backend/gl-profile');
$view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1002604001, $request, $response);
return $view;
}
/**
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return RenderableInterface
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function viewPersonalEntries(RequestAbstract $request, ResponseAbstract $response, array $data = []) : RenderableInterface
{
$view = new View($this->app->l11nManager, $request, $response);
$view->setTemplate('/Modules/Accounting/Theme/Backend/gl-profile');
$view->setTemplate('/Modules/Accounting/Theme/Backend/costobject-profile');
$view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1002604001, $request, $response);
return $view;
@ -406,6 +375,9 @@ final class BackendController extends Controller
$view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1002604001, $request, $response);
$accounts = SupplierMapper::getAll()
->with('account')
->with('mainAddress')
->limit(25)
->execute();
$view->data['accounts'] = $accounts;
@ -432,10 +404,192 @@ final class BackendController extends Controller
$view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1002604001, $request, $response);
$accounts = ClientMapper::getAll()
->with('account')
->with('mainAddress')
->limit(25)
->execute();
$view->data['accounts'] = $accounts;
return $view;
}
/**
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return RenderableInterface
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function viewSupplierProfile(RequestAbstract $request, ResponseAbstract $response, array $data = []) : RenderableInterface
{
$head = $response->data['Content']->head;
$nonce = $this->app->appSettings->getOption('script-nonce');
$head->addAsset(AssetType::CSS, 'Resources/chartjs/chart.css');
$head->addAsset(AssetType::JSLATE, 'Resources/chartjs/chart.js', ['nonce' => $nonce]);
$head->addAsset(AssetType::JSLATE, 'Resources/OpenLayers/OpenLayers.js', ['nonce' => $nonce]);
$head->addAsset(AssetType::JSLATE, 'Modules/Accounting/Controller.js', ['nonce' => $nonce, 'type' => 'module']);
$view = new View($this->app->l11nManager, $request, $response);
$view->setTemplate('/Modules/Accounting/Theme/Backend/personal-profile');
$view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1002604001, $request, $response);
$account = SupplierMapper::get()
->with('account')
->with('mainAddress')
->where('id', (int) $request->getData('id'))
->execute();
$view->data['account'] = $account;
$businessStart = UnitAttributeMapper::get()
->with('type')
->with('value')
->where('ref', $this->app->unitId)
->where('type/name', 'business_year_start')
->execute();
$view->data['business_start'] = $businessStart->id === 0 ? 1 : $businessStart->value->getValue();
$view->data['hasBilling'] = $this->app->moduleManager->isActive('Billing');
/** @var \Model\Setting $settings */
$settings = $this->app->appSettings->get(null, SettingsEnum::DEFAULT_LOCALIZATION);
$view->data['attributeView'] = new \Modules\Attribute\Theme\Backend\Components\AttributeView($this->app->l11nManager, $request, $response);
$view->data['attributeView']->data['default_localization'] = LocalizationMapper::get()->where('id', (int) $settings->id)->execute();
/** @var \Modules\Media\Models\Media[] $files */
$files = MediaMapper::getAll()
->with('types')
->join('id', ClientMapper::class, 'files') // id = media id, files = client relations
->on('id', $account->id, relation: 'files') // id = item id
->execute();
$view->data['files'] = $files;
$view->data['media-upload'] = new \Modules\Media\Theme\Backend\Components\Upload\BaseView($this->app->l11nManager, $request, $response);
$view->data['note'] = new \Modules\Editor\Theme\Backend\Components\Note\BaseView($this->app->l11nManager, $request, $response);
return $view;
}
/**
* Routing end-point for application behavior.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return RenderableInterface
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function viewClientProfile(RequestAbstract $request, ResponseAbstract $response, array $data = []) : RenderableInterface
{
$head = $response->data['Content']->head;
$nonce = $this->app->appSettings->getOption('script-nonce');
$head->addAsset(AssetType::CSS, 'Resources/chartjs/chart.css');
$head->addAsset(AssetType::JSLATE, 'Resources/chartjs/chart.js', ['nonce' => $nonce]);
$head->addAsset(AssetType::JSLATE, 'Resources/OpenLayers/OpenLayers.js', ['nonce' => $nonce]);
$head->addAsset(AssetType::JSLATE, 'Modules/Accounting/Controller.js', ['nonce' => $nonce, 'type' => 'module']);
$view = new View($this->app->l11nManager, $request, $response);
$view->setTemplate('/Modules/Accounting/Theme/Backend/personal-profile');
$view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1002604001, $request, $response);
$account = ClientMapper::get()
->with('account')
->with('contactElements')
->with('mainAddress')
->with('files')->limit(5, 'files')->sort('files/id', OrderType::DESC)
->with('notes')->limit(5, 'notes')->sort('notes/id', OrderType::DESC)
->where('id', (int) $request->getData('id'))
->execute();
$view->data['account'] = $account;
/** @var \Model\Setting $settings */
$settings = $this->app->appSettings->get(null, SettingsEnum::DEFAULT_LOCALIZATION);
$view->data['attributeView'] = new \Modules\Attribute\Theme\Backend\Components\AttributeView($this->app->l11nManager, $request, $response);
$view->data['attributeView']->data['default_localization'] = LocalizationMapper::get()->where('id', (int) $settings->id)->execute();
/** @var \Modules\Attribute\Models\AttributeType[] $attributeTypes */
$attributeTypes = ClientAttributeTypeMapper::getAll()
->with('l11n')
->where('l11n/language', $response->header->l11n->language)
->execute();
$view->data['attributeTypes'] = $attributeTypes;
// Get item profile image
// It might not be part of the 5 newest item files from above
// @todo It would be nice to have something like this as a default method in the model e.g.
// ItemManagement::getRelations()->with('types')->where(...);
// This should return the relations and NOT the model itself
$query = new Builder($this->app->dbPool->get());
$results = $query->selectAs(ClientMapper::HAS_MANY['files']['external'], 'file')
->from(ClientMapper::TABLE)
->leftJoin(ClientMapper::HAS_MANY['files']['table'])
->on(ClientMapper::HAS_MANY['files']['table'] . '.' . ClientMapper::HAS_MANY['files']['self'], '=', ClientMapper::TABLE . '.' . ClientMapper::PRIMARYFIELD)
->leftJoin(MediaMapper::TABLE)
->on(ClientMapper::HAS_MANY['files']['table'] . '.' . ClientMapper::HAS_MANY['files']['external'], '=', MediaMapper::TABLE . '.' . MediaMapper::PRIMARYFIELD)
->leftJoin(MediaMapper::HAS_MANY['types']['table'])
->on(MediaMapper::TABLE . '.' . MediaMapper::PRIMARYFIELD, '=', MediaMapper::HAS_MANY['types']['table'] . '.' . MediaMapper::HAS_MANY['types']['self'])
->leftJoin(MediaTypeMapper::TABLE)
->on(MediaMapper::HAS_MANY['types']['table'] . '.' . MediaMapper::HAS_MANY['types']['external'], '=', MediaTypeMapper::TABLE . '.' . MediaTypeMapper::PRIMARYFIELD)
->where(ClientMapper::HAS_MANY['files']['self'], '=', $account->id)
->where(MediaTypeMapper::TABLE . '.' . MediaTypeMapper::getColumnByMember('name'), '=', 'client_profile_image');
$accountImage = MediaMapper::get()
->with('types')
->where('id', $results)
->limit(1)
->execute();
$view->data['accountImage'] = $accountImage;
$businessStart = UnitAttributeMapper::get()
->with('type')
->with('value')
->where('ref', $this->app->unitId)
->where('type/name', 'business_year_start')
->execute();
$view->data['business_start'] = $businessStart->id === 0 ? 1 : $businessStart->value->getValue();
/** @var \Modules\Auditor\Models\Audit[] $audits */
$audits = AuditMapper::getAll()
->where('type', StringUtils::intHash(ClientMapper::class))
->where('module', 'ClientManagement')
->where('ref', (string) $account->id)
->execute();
$view->data['audits'] = $audits;
/** @var \Modules\Media\Models\Media[] $files */
$files = MediaMapper::getAll()
->with('types')
->join('id', ClientMapper::class, 'files') // id = media id, files = client relations
->on('id', $account->id, relation: 'files') // id = item id
->execute();
$view->data['files'] = $files;
$view->data['media-upload'] = new \Modules\Media\Theme\Backend\Components\Upload\BaseView($this->app->l11nManager, $request, $response);
$view->data['note'] = new \Modules\Editor\Theme\Backend\Components\Note\BaseView($this->app->l11nManager, $request, $response);
$view->data['hasBilling'] = $this->app->moduleManager->isActive('Billing');
return $view;
}
}

View File

@ -35,7 +35,9 @@ class AccountAbstract
*/
public int $id = 0;
public string $account = '';
public string $code = '';
public ?int $account = null;
/*
* String l11n

View File

@ -37,9 +37,10 @@ class AccountAbstractMapper extends DataMapperFactory
*/
public const COLUMNS = [
'accounting_account_id' => ['name' => 'accounting_account_id', 'type' => 'int', 'internal' => 'id'],
'accounting_account_account' => ['name' => 'accounting_account_account', 'type' => 'string', 'internal' => 'account', 'autocomplete' => true],
'accounting_account_code' => ['name' => 'accounting_account_code', 'type' => 'string', 'internal' => 'code', 'autocomplete' => true],
'accounting_account_type' => ['name' => 'accounting_account_type', 'type' => 'int', 'internal' => 'type'],
'accounting_account_parent' => ['name' => 'accounting_account_parent', 'type' => 'int', 'internal' => 'parent'],
'accounting_account_account' => ['name' => 'accounting_account_account', 'type' => 'int', 'internal' => 'account'],
];
/**

View File

@ -46,7 +46,6 @@ return ['Accounting' => [
'Stack' => 'كومة',
'TAccount' => 'T- حساب',
'Text' => 'نص',
'To' => 'ل',
'Total' => 'مجموع',
'Type' => 'نوع',
]];

View File

@ -46,7 +46,6 @@ return ['Accounting' => [
'Stack' => 'Zásobník',
'TAccount' => 'T-Account.',
'Text' => 'Text',
'To' => 'Na',
'Total' => 'Celkový',
'Type' => 'Typ',
]];

View File

@ -46,7 +46,6 @@ return ['Accounting' => [
'Stack' => 'Stak',
'TAccount' => 'T-konto.',
'Text' => 'Tekst',
'To' => 'Til',
'Total' => 'i alt',
'Type' => 'Type',
]];

View File

@ -47,7 +47,41 @@ return ['Accounting' => [
'Stack' => 'Stapel',
'TAccount' => 'T-Konto',
'Text' => 'Text',
'To' => 'Zu',
'Total' => 'Gesamt',
'Type' => 'Typ',
'City' => 'Stadt',
'Zip' => 'Postleitzahl',
'Address' => 'Adresse',
'Country' => 'Land',
'Info' => 'Info',
'Date' => 'Datum',
'Number' => 'Nummer',
'Payment' => 'Zahlung',
'Open' => 'Offen',
'Balanced' => 'Ausgeglichen',
'Balance' => 'Ausgleich',
'YTDSales' => 'Ytd Sales',
'MTDSales' => 'Mtd Sales',
'CLV' => 'CLV',
'LastContact' => 'Letzter Kontakt',
'LastOrder' => 'Letzte Bestellung',
'DSO' => 'DSO',
'Name1' => 'Name 1',
'Name2' => 'Name 2',
'Name3' => 'Name 3',
'Contact' => 'Kontakt',
'Phone' => 'Telefon',
'Email' => 'Email',
'Website' => 'Webseite',
'Postal' => 'Postleitzahl',
'Map' => 'Karte',
'RecentInvoices' => 'Neuste Rechnungen',
'Notes' => 'Notizen',
'Documents' => 'Dokumente',
'CreatedAt' => 'Erstellt',
'Finance' => 'Finanzen',
'Files' => 'Dateien',
'Title' => 'Titel',
'Net' => 'Netto',
'BalanceSheet' => 'Balance Sheet',
]];

View File

@ -46,7 +46,6 @@ return ['Accounting' => [
'Stack' => 'Σωρός',
'TAccount' => 'T-λογαριασμό',
'Text' => 'Κείμενο',
'To' => 'Προς το',
'Total' => 'Σύνολο',
'Type' => 'Τύπος',
]];

View File

@ -47,7 +47,41 @@ return ['Accounting' => [
'Stack' => 'Stack',
'TAccount' => 'T-Account',
'Text' => 'Text',
'To' => 'To',
'Total' => 'Total',
'Type' => 'Type',
'City' => 'City',
'Zip' => 'Zip',
'Address' => 'Address',
'Country' => 'Country',
'Info' => 'Info',
'Date' => 'Date',
'Number' => 'Number',
'Payment' => 'Payment',
'Open' => 'Open',
'Balanced' => 'Balanced',
'Balance' => 'Balance',
'YTDSales' => 'YTD Sales',
'MTDSales' => 'MTD Sales',
'CLV' => 'CLV',
'LastContact' => 'Last Contact',
'LastOrder' => 'Last Order',
'DSO' => 'DSO',
'Name1' => 'Name 1',
'Name2' => 'Name 2',
'Name3' => 'Name 3',
'Contact' => 'Contact',
'Phone' => 'Phone',
'Email' => 'Email',
'Website' => 'Website',
'Postal' => 'Postal',
'Map' => 'Map',
'RecentInvoices' => 'Recent Invoices',
'Notes' => 'Notes',
'Documents' => 'Documents',
'CreatedAt' => 'Created At',
'Finance' => 'Finance',
'Files' => 'Files',
'Title' => 'Title',
'Net' => 'Net',
'BalanceSheet' => 'Balance Sheet',
]];

View File

@ -46,7 +46,6 @@ return ['Accounting' => [
'Stack' => 'Apilar',
'TAccount' => 'Cuenta t',
'Text' => 'Texto',
'To' => 'A',
'Total' => 'Total',
'Type' => 'Escribe',
]];

View File

@ -46,7 +46,6 @@ return ['Accounting' => [
'Stack' => 'Pino',
'TAccount' => 'T-tili',
'Text' => 'Teksti',
'To' => 'Jllek',
'Total' => 'Kaikki yhteensä',
'Type' => 'Tyyppi',
]];

View File

@ -46,7 +46,6 @@ return ['Accounting' => [
'Stack' => 'Empiler',
'TAccount' => 'Compte T-Compte',
'Text' => 'Texte',
'To' => 'À',
'Total' => 'Le total',
'Type' => 'Taper',
]];

View File

@ -46,7 +46,6 @@ return ['Accounting' => [
'Stack' => 'Kazal',
'TAccount' => 'T-számla',
'Text' => 'Szöveg',
'To' => 'Nak nek',
'Total' => 'Teljes',
'Type' => 'típus',
]];

View File

@ -46,7 +46,6 @@ return ['Accounting' => [
'Stack' => 'Pila',
'TAccount' => 'T-ACCOUNT.',
'Text' => 'Testo',
'To' => 'a',
'Total' => 'Totale',
'Type' => 'Tipo',
]];

View File

@ -46,7 +46,6 @@ return ['Accounting' => [
'Stack' => 'スタック',
'TAccount' => 'T - アカウント',
'Text' => '文章',
'To' => 'に',
'Total' => '合計',
'Type' => 'タイプ',
]];

View File

@ -46,7 +46,6 @@ return ['Accounting' => [
'Stack' => '스택',
'TAccount' => 'T-Account.',
'Text' => '텍스트',
'To' => '에게',
'Total' => '총',
'Type' => '유형',
]];

View File

@ -46,7 +46,6 @@ return ['Accounting' => [
'Stack' => 'Stable',
'TAccount' => 'T-konto',
'Text' => 'Tekst',
'To' => 'Til',
'Total' => 'Total',
'Type' => 'Type',
]];

View File

@ -46,7 +46,6 @@ return ['Accounting' => [
'Stack' => 'Stos',
'TAccount' => 'Konta T.',
'Text' => 'Tekst',
'To' => 'Do',
'Total' => 'Całkowity',
'Type' => 'Rodzaj',
]];

View File

@ -46,7 +46,6 @@ return ['Accounting' => [
'Stack' => 'Pilha',
'TAccount' => 'Conta t.',
'Text' => 'Texto',
'To' => 'Para',
'Total' => 'Total',
'Type' => 'Modelo',
]];

View File

@ -46,7 +46,6 @@ return ['Accounting' => [
'Stack' => 'Куча',
'TAccount' => 'T-счет',
'Text' => 'Текст',
'To' => 'К',
'Total' => 'Всего',
'Type' => 'Тип',
]];

View File

@ -46,7 +46,6 @@ return ['Accounting' => [
'Stack' => 'Stack',
'TAccount' => 'T-konto',
'Text' => 'Text',
'To' => 'Till',
'Total' => 'Total',
'Type' => 'Typ',
]];

View File

@ -46,7 +46,6 @@ return ['Accounting' => [
'Stack' => 'ซ้อนกัน',
'TAccount' => 'บัญชี T',
'Text' => 'ข้อความ',
'To' => 'ถึง',
'Total' => 'ทั้งหมด',
'Type' => 'พิมพ์',
]];

View File

@ -46,7 +46,6 @@ return ['Accounting' => [
'Stack' => 'Yığın',
'TAccount' => 'Te hesabı',
'Text' => 'Metin',
'To' => 'İle',
'Total' => 'Toplam',
'Type' => 'Tip',
]];

View File

@ -46,7 +46,6 @@ return ['Accounting' => [
'Stack' => 'Стек',
'TAccount' => 'Т-обліковий запис',
'Text' => 'Текст',
'To' => 'До',
'Total' => 'Загальний',
'Type' => 'Тип',
]];

View File

@ -46,7 +46,6 @@ return ['Accounting' => [
'Stack' => '堆',
'TAccount' => 't账户',
'Text' => '文本',
'To' => '到',
'Total' => '全部的',
'Type' => '类型',
]];

View File

@ -1,12 +0,0 @@
<template id="entry-list-tpl">
<div id="entry-list" class="box" style="z-index: 99; position: relative; top: 20px; display: block; margin: 0 auto; width: 20%;">
<table class="default sticky">
<caption><?= $this->getHtml('Accounts'); ?><i class="g-icon end-xs download btn">download</i></caption>
<thead>
<tr>
<td><?= $this->getHtml('ID', '0', '0'); ?>
<td class="wf-100"><?= $this->getHtml('Account'); ?>
<tbody>
</table>
</div>
</template>

View File

@ -36,7 +36,7 @@ echo $this->data['nav']->render(); ?>
foreach ($accounts as $key => $value) : ++$c;
$url = UriFactory::build('{/base}/accounting/coa/profile?{?}&id=' . $value->id); ?>
<tr data-href="<?= $url; ?>">
<td><a href="<?= $url; ?>"><?= $this->printHtml($value->account); ?></a>
<td><a href="<?= $url; ?>"><?= $this->printHtml($value->code); ?></a>
<td><a href="<?= $url; ?>"><?= $this->printHtml($value->getL11n()); ?></a>
<?php endforeach; ?>
<?php if ($c === 0) : ?>

View File

@ -0,0 +1,125 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\ClientManagement
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
use Modules\ClientManagement\Models\Client;
use phpOMS\Uri\UriFactory;
/** @var \phpOMS\Views\View $this */
$accounts = $this->data['accounts'] ?? [];
$type = \reset($accounts) instanceof Client ? 'client' : 'supplier';
echo $this->data['nav']->render(); ?>
<div class="row">
<div class="col-xs-12">
<section class="portlet">
<div class="portlet-head"><?= $this->getHtml('Accounts'); ?><i class="g-icon download btn end-xs">download</i></div>
<div class="slider">
<table id="iSalesClientList" class="default sticky">
<thead>
<tr>
<td><?= $this->getHtml('ID', '0', '0'); ?>
<label for="iSalesClientList-sort-1">
<input type="radio" name="iSalesClientList-sort" id="iSalesClientList-sort-1">
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="iSalesClientList-sort-2">
<input type="radio" name="iSalesClientList-sort" id="iSalesClientList-sort-2">
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter g-icon">filter_alt</i>
</label>
<td class="wf-100"><?= $this->getHtml('Name'); ?>
<label for="iSalesClientList-sort-3">
<input type="radio" name="iSalesClientList-sort" id="iSalesClientList-sort-3">
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="iSalesClientList-sort-4">
<input type="radio" name="iSalesClientList-sort" id="iSalesClientList-sort-4">
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter g-icon">filter_alt</i>
</label>
<td><?= $this->getHtml('City'); ?>
<label for="iSalesClientList-sort-5">
<input type="radio" name="iSalesClientList-sort" id="iSalesClientList-sort-5">
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="iSalesClientList-sort-6">
<input type="radio" name="iSalesClientList-sort" id="iSalesClientList-sort-6">
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter g-icon">filter_alt</i>
</label>
<td><?= $this->getHtml('Zip'); ?>
<label for="iSalesClientList-sort-7">
<input type="radio" name="iSalesClientList-sort" id="iSalesClientList-sort-7">
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="iSalesClientList-sort-8">
<input type="radio" name="iSalesClientList-sort" id="iSalesClientList-sort-8">
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter g-icon">filter_alt</i>
</label>
<td><?= $this->getHtml('Address'); ?>
<label for="iSalesClientList-sort-9">
<input type="radio" name="iSalesClientList-sort" id="iSalesClientList-sort-9">
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="iSalesClientList-sort-10">
<input type="radio" name="iSalesClientList-sort" id="iSalesClientList-sort-10">
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter g-icon">filter_alt</i>
</label>
<td><?= $this->getHtml('Country'); ?>
<label for="iSalesClientList-sort-11">
<input type="radio" name="iSalesClientList-sort" id="iSalesClientList-sort-11">
<i class="sort-asc g-icon">expand_less</i>
</label>
<label for="iSalesClientList-sort-12">
<input type="radio" name="iSalesClientList-sort" id="iSalesClientList-sort-12">
<i class="sort-desc g-icon">expand_more</i>
</label>
<label>
<i class="filter g-icon">filter_alt</i>
</label>
<tbody>
<?php $count = 0;
foreach ($accounts as $key => $value) : ++$count;
$url = UriFactory::build('{/base}/accounting/' . $type . '/profile?{?}&id=' . $value->id);
?>
<tr data-href="<?= $url; ?>">
<td data-label="<?= $this->getHtml('ID', '0', '0'); ?>"><a href="<?= $url; ?>"><?= $this->printHtml($value->number); ?></a>
<td data-label="<?= $this->getHtml('Name'); ?>"><a href="<?= $url; ?>"><?= $this->printHtml($value->account->name1); ?> <?= $this->printHtml($value->account->name2); ?></a>
<td data-label="<?= $this->getHtml('City'); ?>"><a href="<?= $url; ?>"><?= $this->printHtml($value->mainAddress->city); ?></a>
<td data-label="<?= $this->getHtml('Zip'); ?>"><a href="<?= $url; ?>"><?= $this->printHtml($value->mainAddress->postal); ?></a>
<td data-label="<?= $this->getHtml('Address'); ?>"><a href="<?= $url; ?>"><?= $this->printHtml($value->mainAddress->address); ?></a>
<td data-label="<?= $this->getHtml('Country'); ?>"><a href="<?= $url; ?>"><?= $this->printHtml($value->mainAddress->getCountry()); ?></a>
<?php endforeach; ?>
<?php if ($count === 0) : ?>
<tr><td colspan="8" class="empty"><?= $this->getHtml('Empty', '0', '0'); ?>
<?php endif; ?>
</table>
</div>
</section>
</div>
</div>

View File

@ -0,0 +1,479 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\HumanResourceTimeRecording
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
use Modules\Admin\Models\ContactType;
use Modules\Billing\Models\SalesBillMapper;
use Modules\Media\Models\NullMedia;
use phpOMS\DataStorage\Database\Query\OrderType;
use phpOMS\Localization\ISO639Enum;
use phpOMS\Stdlib\Base\SmartDateTime;
use phpOMS\Uri\UriFactory;
/** @var \phpOMS\Views\View $this */
$account = $this->data['account'] ?? null;
$notes = $account->notes;
$files = $account->files;
$accountImage = $this->getData('accountImage') ?? new NullMedia();
$attributeView = $this->data['attributeView'];
$countryCodes = \phpOMS\Localization\ISO3166TwoEnum::getConstants();
$countries = \phpOMS\Localization\ISO3166NameEnum::getConstants();
$languages = ISO639Enum::getConstants();
echo $this->data['nav']->render(); ?>
<div class="tabview tab-2">
<div class="box">
<ul class="tab-links">
<li><label for="c-tab-1"><?= $this->getHtml('Account'); ?></label>
<li><label for="c-tab-2"><?= $this->getHtml('Finance'); ?></label>
<li><label for="c-tab-7"><?= $this->getHtml('Payment'); ?></label>
<li><label for="c-tab-3"><?= $this->getHtml('Entries'); ?></label>
<li><label for="c-tab-4"><?= $this->getHtml('Address'); ?></label>
<li><label for="c-tab-5"><?= $this->getHtml('Files'); ?></label>
<li><label for="c-tab-6"><?= $this->getHtml('Notes'); ?></label>
</ul>
</div>
<div class="tab-content">
<input type="radio" id="c-tab-1" name="tabular-2"<?= $this->request->uri->fragment === 'c-tab-1' ? ' checked' : ''; ?>>
<div class="tab">
<div class="row">
<div class="col-xs-12 col-lg-3 last-lg">
<div class="box">
<?php if(true) : ?>
<a class="button" href="<?= UriFactory::build('{/base}/sales/bill/create?account=' . $account->id); ?>"><?= $this->getHtml('CreateBill', 'Billing'); ?></a>
<?php endif; ?>
<?php if (false) : ?>
<a class="button"><?= $this->getHtml('ViewAccount', 'Accounting'); ?></a>
<?php endif; ?>
</div>
<section class="portlet">
<form>
<div class="portlet-body">
<div class="form-group">
<label for="iId"><?= $this->getHtml('ID', '0', '0'); ?></label>
<span class="input"><button type="button" formaction=""><i class="g-icon">book</i></button><input type="number" id="iId" min="1" name="id" value="<?= $this->printHtml($account->number); ?>" disabled></span>
</div>
<div class="form-group">
<label for="iName1"><?= $this->getHtml('Name1'); ?></label>
<input type="text" id="iName1" name="name1" value="<?= $this->printHtml($account->account->name1); ?>" required>
</div>
<div class="form-group">
<label for="iName2"><?= $this->getHtml('Name2'); ?></label>
<input type="text" id="iName2" name="name2" value="<?= $this->printHtml($account->account->name2); ?>">
</div>
<div class="form-group">
<label for="iName3"><?= $this->getHtml('Name3'); ?></label>
<input type="text" id="iName3" name="name3" value="<?= $this->printHtml($account->account->name3); ?>">
</div>
</div>
<div class="portlet-foot">
<input type="submit" value="<?= $this->getHtml('Save', '0', '0'); ?>" name="save-account-profile"> <input type="submit" value="<?= $this->getHtml('Delete', '0', '0'); ?>" name="delete-account-profile">
</div>
</form>
</section>
<section class="portlet">
<div class="portlet-head">
<?= $this->getHtml('Contact'); ?>
<a class="end-xs" href=""><i class="g-icon btn">mail</i></a>
</div>
<div class="portlet-body">
<div class="form-group">
<label for="iPhone"><?= $this->getHtml('Phone'); ?></label>
<input type="text" id="iPhone" name="name1" value="<?= $this->printHtml($account->getMainContactElement(ContactType::PHONE)->content); ?>">
</div>
<div class="form-group">
<label for="iEmail"><?= $this->getHtml('Email'); ?></label>
<input type="text" id="iEmail" name="name1" value="<?= $this->printHtml($account->getMainContactElement(ContactType::EMAIL)->content); ?>">
</div>
<div class="form-group">
<label for="iWebsite"><?= $this->getHtml('Website'); ?></label>
<input type="text" id="iWebsite" name="name1" value="<?= $this->printHtml($account->getMainContactElement(ContactType::WEBSITE)->content); ?>">
</div>
</div>
</section>
<section class="portlet map-small">
<div class="portlet-head">
<?= $this->getHtml('Address'); ?>
<span class="clickPopup end-xs">
<label for="addressDropdown"><i class="g-icon btn">print</i></label>
<input id="addressDropdown" name="addressDropdown" type="checkbox">
<div class="popup">
<ul>
<li>
<input id="id1" type="checkbox">
<ul>
<li>
<label for="id1">
<a href="" class="button">Word</a>
<span></span>
<i class="g-icon expand">chevron_right</i>
</label>
<li>Letter
</ul>
<li><label class="button cancel" for="addressDropdown">Cancel</label>
</ul>
</div>
</span>
</div>
<div class="portlet-body">
<?php if (!empty($account->mainAddress->fao)) : ?>
<div class="form-group">
<label for="iFAO"><?= $this->getHtml('FAO'); ?></label>
<input type="text" id="iFAO" name="fao" value="<?= $this->printHtml($account->mainAddress->fao); ?>">
</div>
<?php endif; ?>
<div class="form-group">
<label for="iAddress"><?= $this->getHtml('Address'); ?></label>
<input type="text" id="iAddress" name="address" value="<?= $this->printHtml($account->mainAddress->address); ?>" required>
</div>
<?php if (!empty($account->mainAddress->addressAddition)) : ?>
<div class="form-group">
<label for="iAddition"><?= $this->getHtml('Addition'); ?></label>
<input type="text" id="iAddition" name="addition" value="<?= $this->printHtml($account->mainAddress->addressAddition); ?>">
</div>
<?php endif; ?>
<div class="form-group">
<label for="iPostal"><?= $this->getHtml('Postal'); ?></label>
<input type="text" id="iPostal" name="postal" value="<?= $this->printHtml($account->mainAddress->postal); ?>" required>
</div>
<div class="form-group">
<label for="iCity"><?= $this->getHtml('City'); ?></label>
<input type="text" id="iCity" name="city" value="<?= $this->printHtml($account->mainAddress->city); ?>" required>
</div>
<div class="form-group">
<label for="iCountry"><?= $this->getHtml('Country'); ?></label>
<select id="iCountry" name="country">
<?php foreach ($countryCodes as $code3 => $code2) : ?>
<option value="<?= $this->printHtml($code2); ?>"<?= $this->printHtml($code2 === $account->mainAddress->getCountry() ? ' selected' : ''); ?>><?= $this->printHtml($countries[$code3]); ?>
<?php endforeach; ?>
</select>
</div>
<div class="form-group">
<label for="iClientMap"><?= $this->getHtml('Map'); ?></label>
<div id="iClientMap" class="map" data-lat="<?= $account->mainAddress->lat; ?>" data-lon="<?= $account->mainAddress->lon; ?>"></div>
</div>
</div>
</section>
<section class="portlet">
<div class="portlet-body">
<img alt="<?= $this->printHtml($accountImage->name); ?>" width="100%" loading="lazy" class="item-image"
src="<?= $accountImage->id === 0
? 'Web/Backend/img/logo_grey.png'
: UriFactory::build($accountImage->getPath()); ?>">
</div>
</section>
<section class="portlet highlight-4">
<div class="portlet-body">
<textarea class="undecorated"><?= $this->printHtml($account->info); ?></textarea>
</div>
</section>
</div>
<div class="col-xs-12 col-lg-9 plain-grid">
<?php if (!empty($notes) && ($warning = $account->getEditorDocByTypeName('account_backend_warning'))->id !== 0) : ?>
<!-- If note warning exists -->
<div class="row">
<div class="col-xs-12">
<section class="portlet highlight-1">
<div class="portlet-body"><?= $this->printHtml($warning->plain); ?></div>
</section>
</div>
</div>
<?php endif; ?>
<?php if ($this->data['hasBilling']) : ?>
<div class="row">
<div class="col-xs-12 col-lg-4">
<section class="portlet highlight-7">
<div class="portlet-body">
<table class="wf-100">
<tr><td><?= $this->getHtml('YTDSales'); ?>:
<td><?= $this->getCurrency(SalesBillMapper::getClientNetSales($account->id, SmartDateTime::startOfYear($this->data['business_start']), new \DateTime('now')), format: 'medium'); ?>
<tr><td><?= $this->getHtml('MTDSales'); ?>:
<td><?= $this->getCurrency(SalesBillMapper::getClientNetSales($account->id, SmartDateTime::startOfMonth(), new \DateTime('now')), format: 'medium'); ?>
<tr><td><?= $this->getHtml('CLV'); ?>:
<td><?= $this->getCurrency(SalesBillMapper::getCLVHistoric($account->id), format: 'medium'); ?>
</table>
</div>
</section>
</div>
<div class="col-xs-12 col-lg-4">
<section class="portlet highlight-2">
<div class="portlet-body">
<table class="wf-100">
<tr><td><?= $this->getHtml('LastContact'); ?>:
<td><?= SalesBillMapper::getClientLastOrder($account->id)?->format('Y-m-d'); ?>
<tr><td><?= $this->getHtml('LastOrder'); ?>:
<td><?= SalesBillMapper::getClientLastOrder($account->id)?->format('Y-m-d'); ?>
<tr><td><?= $this->getHtml('Created'); ?>:
<td><?= $account->createdAt->format('Y-m-d H:i'); ?>
</table>
</div>
</section>
</div>
<div class="col-xs-12 col-lg-4">
<section class="portlet highlight-3">
<div class="portlet-body">
<table class="wf-100">
<tr><td><?= $this->getHtml('DSO'); ?>:
<td>TBD
<tr><td><?= $this->getHtml('Due'); ?>:
<td>TBD
<tr><td><?= $this->getHtml('Balance'); ?>:
<td>TBD
</table>
</div>
</section>
</div>
</div>
<?php endif; ?>
<div class="row">
<div class="col-xs-12 col-md-6">
<section class="portlet">
<div class="portlet-head"><?= $this->getHtml('Notes'); ?></div>
<div class="slider">
<table id="iNotesItemList" class="default sticky">
<thead>
<tr>
<td class="wf-100"><?= $this->getHtml('Title'); ?>
<td><?= $this->getHtml('CreatedAt'); ?>
<tbody>
<?php foreach ($notes as $note) :
$url = UriFactory::build('{/base}/editor/single?{?}&id=' . $note->id);
?>
<tr data-href="<?= $url; ?>">
<td><a href="<?= $url; ?>"><?= $note->title; ?></a>
<td><a href="<?= $url; ?>"><?= $note->createdAt->format('Y-m-d'); ?></a>
<?php endforeach; ?>
</table>
</div>
</section>
</div>
<div class="col-xs-12 col-md-6">
<section class="portlet">
<div class="portlet-head"><?= $this->getHtml('Documents'); ?></div>
<div class="slider">
<table id="iFilesClientList" class="default sticky">
<thead>
<tr>
<td class="wf-100"><?= $this->getHtml('Title'); ?>
<td>
<td><?= $this->getHtml('CreatedAt'); ?>
<tbody>
<?php foreach ($files as $file) :
$url = UriFactory::build('{/base}/media/single?{?}&id=' . $file->id);
?>
<tr data-href="<?= $url; ?>">
<td><a href="<?= $url; ?>"><?= $file->name; ?></a>
<td><a href="<?= $url; ?>"><?= $file->extension; ?></a>
<td><a href="<?= $url; ?>"><?= $file->createdAt->format('Y-m-d'); ?></a>
<?php endforeach; ?>
</table>
</div>
</section>
</div>
</div>
<?php if ($this->data['hasBilling']) : ?>
<div class="row">
<div class="col-xs-12">
<section class="portlet">
<div class="portlet-head"><?= $this->getHtml('RecentInvoices'); ?></div>
<table id="iSalesItemList" class="default sticky">
<thead>
<tr>
<td><?= $this->getHtml('Number'); ?>
<td><?= $this->getHtml('Type'); ?>
<td class="wf-100"><?= $this->getHtml('Name'); ?>
<td><?= $this->getHtml('Net'); ?>
<td><?= $this->getHtml('Date'); ?>
<tbody>
<?php
$newestInvoices = SalesBillMapper::getAll()
->with('type')
->with('type/l11n')
->with('account')
->where('account', $account->id)
->where('type/l11n/language', $this->response->header->l11n->language)
->sort('id', OrderType::DESC)
->limit(5)
->execute();
/** @var \Modules\Billing\Models\Bill $invoice */
foreach ($newestInvoices as $invoice) :
$url = UriFactory::build('{/base}/sales/bill?{?}&id=' . $invoice->id);
?>
<tr data-href="<?= $url; ?>">
<td><a href="<?= $url; ?>"><?= $invoice->getNumber(); ?></a>
<td><a href="<?= $url; ?>"><?= $invoice->type->getL11n(); ?></a>
<td><a href="<?= $url; ?>"><?= $invoice->billTo; ?></a>
<td><a href="<?= $url; ?>"><?= $this->getCurrency($invoice->netSales); ?></a>
<td><a href="<?= $url; ?>"><?= $invoice->createdAt->format('Y-m-d'); ?></a>
<?php endforeach; ?>
</table>
</section>
</div>
</div>
<?php endif; ?>
</div>
</div>
</div>
<input type="radio" id="c-tab-2" name="tabular-2"<?= $this->request->uri->fragment === 'c-tab-2' ? ' checked' : ''; ?>>
<div class="tab">
<div class="row">
<div class="col-xs-12 col-sm-6">
<section class="portlet">
<div class="portlet-head"><?= $this->getHtml('Account'); ?></div>
<div class="portlet-body">
<div class="form-group">
<label for="iBalanceSheet"><?= $this->getHtml('BalanceSheet'); ?></label>
<input id="iBalanceSheet" type="text">
</div>
</div>
</section>
</div>
<div class="col-xs-12 col-sm-6">
<section class="portlet">
<div class="portlet-head"><?= $this->getHtml('Accounts'); ?></div>
<div class="slider">
<table class="default sticky">
<thead>
<tr>
<td>
<tbody>
<tr>
<td>
</table>
</div>
</section>
</div>
</div>
</div>
<input type="radio" id="c-tab-7" name="tabular-2"<?= $this->request->uri->fragment === 'c-tab-7' ? ' checked' : ''; ?>>
<div class="tab">
<div class="row">
</div>
</div>
<input type="radio" id="c-tab-3" name="tabular-2"<?= $this->request->uri->fragment === 'c-tab-3' ? ' checked' : ''; ?>>
<div class="tab">
<div class="row">
<div class="col-xs-12 col-lg-3 last-lg">
<section class="portlet">
<div class="portlet-head"><?= $this->getHtml('QuickAction'); ?></div>
<div class="portlet-body">
</div>
</section>
</div>
<div class="col-xs-12 col-lg-9 plain-grid">
<div class="row">
<div class="col-xs-12">
<section class="portlet col-simple" style="height: 350px;">
<div class="portlet-head top-xs"><?= $this->getHtml('Open'); ?></div>
<table id="iSalesItemList" class="default sticky">
<thead>
<tr>
<td>
<td><?= $this->getHtml('Info'); ?>
<td><?= $this->getHtml('Date'); ?>
<td><?= $this->getHtml('Credit'); ?>
<td><?= $this->getHtml('Debit'); ?>
<td><?= $this->getHtml('Number'); ?>
<td class="wf-100"><?= $this->getHtml('Text'); ?>
<td><?= $this->getHtml('Due'); ?>
<td><?= $this->getHtml('Payment'); ?>
<tbody>
<tr>
<td colspan="9" class="empty"><?= $this->getHtml('Empty', '0', '0'); ?>
</table>
<div class="portlet-body col-xs"></div>
<div class="portlet-foot bottom-xs">
<?= $this->getHtml('Total'); ?>: 0.00
<?= $this->getHtml('Due'); ?>: 0.00
</div>
</section>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<section class="portlet col-simple" style="height: 350px;">
<div class="portlet-head top-xs"><?= $this->getHtml('Total'); ?></div>
<table id="iSalesItemList" class="default sticky">
<thead>
<tr>
<td><?= $this->getHtml('Info'); ?>
<td><?= $this->getHtml('Date'); ?>
<td><?= $this->getHtml('Credit'); ?>
<td><?= $this->getHtml('Debit'); ?>
<td><?= $this->getHtml('Number'); ?>
<td class="wf-100"><?= $this->getHtml('Text'); ?>
<td><?= $this->getHtml('Due'); ?>
<td><?= $this->getHtml('Payment'); ?>
<td><?= $this->getHtml('Balanced'); ?>
<td><?= $this->getHtml('Balance'); ?>
<tbody>
<tr>
<td colspan="10" class="empty"><?= $this->getHtml('Empty', '0', '0'); ?>
</table>
<div class="portlet-body col-xs"></div>
</section>
</div>
</div>
</div>
</div>
</div>
<input type="radio" id="c-tab-4" name="tabular-2"<?= $this->request->uri->fragment === 'c-tab-4' ? ' checked' : ''; ?>>
<div class="tab">
</div>
<input type="radio" id="c-tab-5" name="tabular-2"<?= $this->request->uri->fragment === 'c-tab-5' ? ' checked' : ''; ?>>
<div class="tab">
<?= $this->data['media-upload']->render('account-file', 'files', '', $account->files); ?>
</div>
<input type="radio" id="c-tab-6" name="tabular-2"<?= $this->request->uri->fragment === 'c-tab-6' ? ' checked' : ''; ?>>
<div class="tab">
<?= $this->data['note']->render('account-note', 'notes', $account->notes); ?>
</div>
</div>
</div>