reports
This commit is contained in:
parent
447dd3aa69
commit
05e29a2ea3
|
|
@ -0,0 +1 @@
|
|||
/vendor/
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# How to contribute
|
||||
|
||||
Contributions to this project are highly welcome.
|
||||
|
||||
1. Submit your pull requests to the `develop` branch
|
||||
1. Adhere to the [PSR-2 coding](http://www.php-fig.org/psr/psr-2/) standard
|
||||
1. If you are not sure if your ideas are fit for this project, create an issue and ask
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2016 OFFLINE GmbH
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
<?php namespace OFFLINE\CORS;
|
||||
|
||||
use OFFLINE\CORS\Classes\HandleCors;
|
||||
use OFFLINE\CORS\Classes\HandlePreflight;
|
||||
use OFFLINE\CORS\Classes\ServiceProvider;
|
||||
use OFFLINE\CORS\Models\Settings;
|
||||
use System\Classes\PluginBase;
|
||||
|
||||
class Plugin extends PluginBase
|
||||
{
|
||||
public function boot()
|
||||
{
|
||||
\App::register(ServiceProvider::class);
|
||||
|
||||
$this->app['Illuminate\Contracts\Http\Kernel']
|
||||
->prependMiddleware(HandleCors::class);
|
||||
|
||||
if (request()->isMethod('OPTIONS')) {
|
||||
$this->app['Illuminate\Contracts\Http\Kernel']
|
||||
->prependMiddleware(HandlePreflight::class);
|
||||
}
|
||||
}
|
||||
|
||||
public function registerPermissions()
|
||||
{
|
||||
return [
|
||||
'offline.cors.manage' => [
|
||||
'label' => 'Can manage cors settings',
|
||||
'tab' => 'CORS',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function registerSettings()
|
||||
{
|
||||
return [
|
||||
'cors' => [
|
||||
'label' => 'CORS-Settings',
|
||||
'description' => 'Manage CORS headers',
|
||||
'category' => 'system::lang.system.categories.cms',
|
||||
'icon' => 'icon-code',
|
||||
'class' => Settings::class,
|
||||
'order' => 500,
|
||||
'keywords' => 'cors',
|
||||
'permissions' => ['offline.cors.manage'],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
# CORS plugin for October CMS
|
||||
|
||||
This plugin is based on [https://github.com/barryvdh/laravel-cors](https://github.com/barryvdh/laravel-cors/blob/master/config/cors.php).
|
||||
|
||||
All configuration for the plugin can be done via the backend settings.
|
||||
|
||||
The following cors headers are supported:
|
||||
|
||||
* Access-Control-Allow-Origin
|
||||
* Access-Control-Allow-Headers
|
||||
* Access-Control-Allow-Methods
|
||||
* Access-Control-Allow-Credentials
|
||||
* Access-Control-Expose-Headers
|
||||
* Access-Control-Max-Age
|
||||
|
||||
Currently these headers are sent for every request. There is no per-route configuration possible at this time.
|
||||
|
||||
## Setup
|
||||
|
||||
After installing the plugin visit the CORS settings page in your October CMS backend settings.
|
||||
|
||||
You can add `*` as an entry to `Allowed origins`, `Allowed headers` and `Allowed methods` to allow any kind of CORS request from everywhere.
|
||||
|
||||
It is advised to be more explicit about these settings. You can add values for each header via the repeater fields.
|
||||
|
||||
> It is important to set these intial settings once for the plugin to work as excpected!
|
||||
|
||||
### Filesystem configuration
|
||||
|
||||
As an alternative to the backend settings you can create a `config/config.php` file in the plugins root directory to configure it.
|
||||
|
||||
The filesystem configuration will overwrite any defined backend setting.
|
||||
|
||||
```php
|
||||
<?php
|
||||
// plugins/offline/cors/config/config.php
|
||||
return [
|
||||
'supportsCredentials' => true,
|
||||
'maxAge' => 3600,
|
||||
'allowedOrigins' => ['*'],
|
||||
'allowedHeaders' => ['*'],
|
||||
'allowedMethods' => ['GET', 'POST'],
|
||||
'exposedHeaders' => [''],
|
||||
];
|
||||
```
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace OFFLINE\CORS\Classes;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
|
||||
/**
|
||||
* Based on asm89/stack-cors
|
||||
*/
|
||||
class Cors implements HttpKernelInterface
|
||||
{
|
||||
/**
|
||||
* @var \Symfony\Component\HttpKernel\HttpKernelInterface
|
||||
*/
|
||||
private $app;
|
||||
|
||||
/**
|
||||
* @var CorsService
|
||||
*/
|
||||
private $cors;
|
||||
|
||||
private $defaultOptions = [
|
||||
'allowedHeaders' => [],
|
||||
'allowedMethods' => [],
|
||||
'allowedOrigins' => [],
|
||||
'exposedHeaders' => false,
|
||||
'maxAge' => false,
|
||||
'supportsCredentials' => false,
|
||||
];
|
||||
|
||||
/**
|
||||
* Cors constructor.
|
||||
*
|
||||
* @param HttpKernelInterface $app
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct(HttpKernelInterface $app, array $options = [])
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->cors = new CorsService(array_merge($this->defaultOptions, $options));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param int $type
|
||||
* @param bool $catch
|
||||
*
|
||||
* @return bool|Response
|
||||
*/
|
||||
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
|
||||
{
|
||||
if ( ! $this->cors->isCorsRequest($request)) {
|
||||
return $this->app->handle($request, $type, $catch);
|
||||
}
|
||||
|
||||
if ($this->cors->isPreflightRequest($request)) {
|
||||
return $this->cors->handlePreflightRequest($request);
|
||||
}
|
||||
|
||||
if ( ! $this->cors->isActualRequestAllowed($request)) {
|
||||
return new Response('Not allowed.', 403);
|
||||
}
|
||||
|
||||
$response = $this->app->handle($request, $type, $catch);
|
||||
|
||||
return $this->cors->addActualRequestHeaders($response, $request);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,199 @@
|
|||
<?php
|
||||
|
||||
namespace OFFLINE\CORS\Classes;
|
||||
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* Based on asm89/stack-cors
|
||||
*/
|
||||
class CorsService
|
||||
{
|
||||
private $options;
|
||||
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
$this->options = $this->normalizeOptions($options);
|
||||
}
|
||||
|
||||
private function normalizeOptions(array $options = [])
|
||||
{
|
||||
$options += [
|
||||
'supportsCredentials' => false,
|
||||
'maxAge' => 0,
|
||||
];
|
||||
|
||||
// Make sure these values are arrays, if not specified in the backend settings.
|
||||
$arrayKeys = [
|
||||
'allowedOrigins',
|
||||
'allowedHeaders',
|
||||
'exposedHeaders',
|
||||
'allowedMethods',
|
||||
];
|
||||
|
||||
foreach ($arrayKeys as $key) {
|
||||
if (!$options[$key]) {
|
||||
$options[$key] = [];
|
||||
}
|
||||
}
|
||||
|
||||
// normalize array('*') to true
|
||||
if (in_array('*', $options['allowedOrigins'])) {
|
||||
$options['allowedOrigins'] = true;
|
||||
}
|
||||
if (in_array('*', $options['allowedHeaders'])) {
|
||||
$options['allowedHeaders'] = true;
|
||||
} else {
|
||||
$options['allowedHeaders'] = array_map('strtolower', $options['allowedHeaders']);
|
||||
}
|
||||
|
||||
if (in_array('*', $options['allowedMethods'])) {
|
||||
$options['allowedMethods'] = true;
|
||||
} else {
|
||||
$options['allowedMethods'] = array_map('strtoupper', $options['allowedMethods']);
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
public function isActualRequestAllowed(Request $request)
|
||||
{
|
||||
return $this->checkOrigin($request);
|
||||
}
|
||||
|
||||
public function isCorsRequest(Request $request)
|
||||
{
|
||||
return $request->headers->has('Origin') && $request->headers->get('Origin') !== $request->getSchemeAndHttpHost();
|
||||
}
|
||||
|
||||
public function isPreflightRequest(Request $request)
|
||||
{
|
||||
return $this->isCorsRequest($request)
|
||||
&& $request->getMethod() === 'OPTIONS'
|
||||
&& $request->headers->has('Access-Control-Request-Method');
|
||||
}
|
||||
|
||||
public function addActualRequestHeaders(Response $response, Request $request)
|
||||
{
|
||||
if ( ! $this->checkOrigin($request)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$response->headers->set('Access-Control-Allow-Origin', $request->headers->get('Origin'));
|
||||
|
||||
if ( ! $response->headers->has('Vary')) {
|
||||
$response->headers->set('Vary', 'Origin');
|
||||
} else {
|
||||
$response->headers->set('Vary', $response->headers->get('Vary') . ', Origin');
|
||||
}
|
||||
|
||||
if ($this->options['supportsCredentials']) {
|
||||
$response->headers->set('Access-Control-Allow-Credentials', 'true');
|
||||
}
|
||||
|
||||
if ($this->options['exposedHeaders']) {
|
||||
$response->headers->set('Access-Control-Expose-Headers', implode(', ', $this->options['exposedHeaders']));
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function handlePreflightRequest(Request $request)
|
||||
{
|
||||
if (true !== $check = $this->checkPreflightRequestConditions($request)) {
|
||||
return $check;
|
||||
}
|
||||
|
||||
return $this->buildPreflightCheckResponse($request);
|
||||
}
|
||||
|
||||
private function buildPreflightCheckResponse(Request $request)
|
||||
{
|
||||
$response = new Response();
|
||||
|
||||
if ($this->options['supportsCredentials']) {
|
||||
$response->headers->set('Access-Control-Allow-Credentials', 'true');
|
||||
}
|
||||
|
||||
$response->headers->set('Access-Control-Allow-Origin', $request->headers->get('Origin'));
|
||||
|
||||
if ($this->options['maxAge']) {
|
||||
$response->headers->set('Access-Control-Max-Age', $this->options['maxAge']);
|
||||
}
|
||||
|
||||
$allowMethods = $this->options['allowedMethods'] === true
|
||||
? strtoupper($request->headers->get('Access-Control-Request-Method'))
|
||||
: implode(', ', $this->options['allowedMethods']);
|
||||
$response->headers->set('Access-Control-Allow-Methods', $allowMethods);
|
||||
|
||||
$allowHeaders = $this->options['allowedHeaders'] === true
|
||||
? strtoupper($request->headers->get('Access-Control-Request-Headers'))
|
||||
: implode(', ', $this->options['allowedHeaders']);
|
||||
$response->headers->set('Access-Control-Allow-Headers', $allowHeaders);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function checkPreflightRequestConditions(Request $request)
|
||||
{
|
||||
if ( ! $this->checkOrigin($request)) {
|
||||
return $this->createBadRequestResponse(403, 'Origin not allowed');
|
||||
}
|
||||
|
||||
if ( ! $this->checkMethod($request)) {
|
||||
return $this->createBadRequestResponse(405, 'Method not allowed');
|
||||
}
|
||||
|
||||
$requestHeaders = [];
|
||||
// if allowedHeaders has been set to true ('*' allow all flag) just skip this check
|
||||
if ($this->options['allowedHeaders'] !== true && $request->headers->has('Access-Control-Request-Headers')) {
|
||||
$headers = strtolower($request->headers->get('Access-Control-Request-Headers'));
|
||||
$requestHeaders = explode(',', $headers);
|
||||
|
||||
foreach ($requestHeaders as $header) {
|
||||
if ( ! in_array(trim($header), $this->options['allowedHeaders'])) {
|
||||
return $this->createBadRequestResponse(403, 'Header not allowed');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function createBadRequestResponse($code, $reason = '')
|
||||
{
|
||||
return new Response($reason, $code);
|
||||
}
|
||||
|
||||
private function checkOrigin(Request $request)
|
||||
{
|
||||
if ($this->options['allowedOrigins'] === true) {
|
||||
// allow all '*' flag
|
||||
return true;
|
||||
}
|
||||
$origin = $request->headers->get('Origin');
|
||||
|
||||
foreach ($this->options['allowedOrigins'] as $allowedOrigin) {
|
||||
if (OriginMatcher::matches($allowedOrigin, $origin)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function checkMethod(Request $request)
|
||||
{
|
||||
if ($this->options['allowedMethods'] === true) {
|
||||
// allow all '*' flag
|
||||
return true;
|
||||
}
|
||||
|
||||
$requestMethod = strtoupper($request->headers->get('Access-Control-Request-Method'));
|
||||
|
||||
return in_array($requestMethod, $this->options['allowedMethods']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace OFFLINE\CORS\Classes;
|
||||
|
||||
use Closure;
|
||||
|
||||
class HandleCors
|
||||
{
|
||||
/**
|
||||
* The CORS service
|
||||
*
|
||||
* @var CorsService
|
||||
*/
|
||||
protected $cors;
|
||||
|
||||
/**
|
||||
* @param CorsService $cors
|
||||
*/
|
||||
public function __construct(CorsService $cors)
|
||||
{
|
||||
$this->cors = $cors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming request. Based on Asm89\Stack\Cors by asm89
|
||||
* @see https://github.com/asm89/stack-cors/blob/master/src/Asm89/Stack/Cors.php
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
if ( ! $this->cors->isCorsRequest($request)) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
if ( ! $this->cors->isActualRequestAllowed($request)) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
/** @var \Illuminate\Http\Response $response */
|
||||
$response = $next($request);
|
||||
|
||||
return $this->cors->addActualRequestHeaders($response, $request);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
namespace OFFLINE\CORS\Classes;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Http\Kernel;
|
||||
use Illuminate\Routing\Router;
|
||||
|
||||
class HandlePreflight
|
||||
{
|
||||
/**
|
||||
* @param CorsService $cors
|
||||
*/
|
||||
public function __construct(CorsService $cors, Router $router, Kernel $kernel)
|
||||
{
|
||||
$this->cors = $cors;
|
||||
$this->router = $router;
|
||||
$this->kernel = $kernel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming OPTIONS request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$response = $next($request);
|
||||
if ($this->cors->isPreflightRequest($request) && $this->hasMatchingCorsRoute($request)) {
|
||||
$preflight = $this->cors->handlePreflightRequest($request);
|
||||
$response->headers->add($preflight->headers->all());
|
||||
}
|
||||
$response->setStatusCode(204);
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the current OPTIONS request matches a CORS-enabled route
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function hasMatchingCorsRoute($request)
|
||||
{
|
||||
// Check if CORS is added in a global middleware
|
||||
if ($this->kernel->hasMiddleware(HandleCors::class)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if CORS is added as a route middleware
|
||||
$request = clone $request;
|
||||
$request->setMethod($request->header('Access-Control-Request-Method'));
|
||||
|
||||
try {
|
||||
$route = $this->router->getRoutes()->match($request);
|
||||
// change of method name in laravel 5.3
|
||||
if (method_exists($this->router, 'gatherRouteMiddleware')) {
|
||||
$middleware = $this->router->gatherRouteMiddleware($route);
|
||||
} else {
|
||||
$middleware = $this->router->gatherRouteMiddlewares($route);
|
||||
}
|
||||
|
||||
return in_array(HandleCors::class, $middleware);
|
||||
} catch (\Exception $e) {
|
||||
app('log')->error($e);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
namespace OFFLINE\CORS\Classes;
|
||||
|
||||
class OriginMatcher
|
||||
{
|
||||
|
||||
public static function matches($pattern, $origin)
|
||||
{
|
||||
if ($pattern === $origin) {
|
||||
return true;
|
||||
}
|
||||
$scheme = parse_url($origin, PHP_URL_SCHEME);
|
||||
$host = parse_url($origin, PHP_URL_HOST);
|
||||
$port = parse_url($origin, PHP_URL_PORT);
|
||||
|
||||
$schemePattern = static::parseOriginPattern($pattern, PHP_URL_SCHEME);
|
||||
$hostPattern = static::parseOriginPattern($pattern, PHP_URL_HOST);
|
||||
$portPattern = static::parseOriginPattern($pattern, PHP_URL_PORT);
|
||||
|
||||
$schemeMatches = static::schemeMatches($schemePattern, $scheme);
|
||||
$hostMatches = static::hostMatches($hostPattern, $host);
|
||||
$portMatches = static::portMatches($portPattern, $port);
|
||||
|
||||
return $schemeMatches && $hostMatches && $portMatches;
|
||||
}
|
||||
|
||||
public static function schemeMatches($pattern, $scheme)
|
||||
{
|
||||
return is_null($pattern) || $pattern === $scheme;
|
||||
}
|
||||
|
||||
public static function hostMatches($pattern, $host)
|
||||
{
|
||||
$patternComponents = array_reverse(explode('.', $pattern));
|
||||
$hostComponents = array_reverse(explode('.', $host));
|
||||
foreach ($patternComponents as $index => $patternComponent) {
|
||||
if ($patternComponent === '*') {
|
||||
return true;
|
||||
}
|
||||
if ( ! isset($hostComponents[$index])) {
|
||||
return false;
|
||||
}
|
||||
if ($hostComponents[$index] !== $patternComponent) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return count($patternComponents) === count($hostComponents);
|
||||
}
|
||||
|
||||
public static function portMatches($pattern, $port)
|
||||
{
|
||||
if ($pattern === "*") {
|
||||
return true;
|
||||
}
|
||||
if ((string)$pattern === "") {
|
||||
return (string)$port === "";
|
||||
}
|
||||
if (preg_match('/\A\d+\z/', $pattern)) {
|
||||
return (string)$pattern === (string)$port;
|
||||
}
|
||||
if (preg_match('/\A(?P<from>\d+)-(?P<to>\d+)\z/', $pattern, $captured)) {
|
||||
return $captured['from'] <= $port && $port <= $captured['to'];
|
||||
}
|
||||
throw new \InvalidArgumentException("Invalid port pattern: ${pattern}");
|
||||
}
|
||||
|
||||
public static function parseOriginPattern($originPattern, $component = -1)
|
||||
{
|
||||
$matched = preg_match(
|
||||
'!\A
|
||||
(?: (?P<scheme> ([a-z][a-z0-9+\-.]*) ):// )?
|
||||
(?P<host> (?:\*|[\w-]+)(?:\.[\w-]+)* )
|
||||
(?: :(?P<port> (?: \*|\d+(?:-\d+)? ) ) )?
|
||||
\z!x',
|
||||
$originPattern,
|
||||
$captured
|
||||
);
|
||||
if ( ! $matched) {
|
||||
throw new \InvalidArgumentException("Invalid origin pattern ${originPattern}");
|
||||
}
|
||||
$components = [
|
||||
'scheme' => $captured['scheme'] ?: null,
|
||||
'host' => $captured['host'],
|
||||
'port' => array_key_exists('port', $captured) ? $captured['port'] : null,
|
||||
];
|
||||
switch ($component) {
|
||||
case -1:
|
||||
return $components;
|
||||
case PHP_URL_SCHEME:
|
||||
return $components['scheme'];
|
||||
case PHP_URL_HOST:
|
||||
return $components['host'];
|
||||
case PHP_URL_PORT:
|
||||
return $components['port'];
|
||||
}
|
||||
throw new \InvalidArgumentException("Invalid component: ${component}");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
namespace OFFLINE\CORS\Classes;
|
||||
|
||||
use October\Rain\Support\ServiceProvider as BaseServiceProvider;
|
||||
use OFFLINE\CORS\Models\Settings;
|
||||
|
||||
class ServiceProvider extends BaseServiceProvider
|
||||
{
|
||||
/**
|
||||
* Indicates if loading of the provider is deferred.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $defer = false;
|
||||
|
||||
/**
|
||||
* Register the service provider.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->app->singleton(CorsService::class, function ($app) {
|
||||
return new CorsService($this->getSettings());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return default Settings
|
||||
*/
|
||||
protected function getSettings()
|
||||
{
|
||||
$supportsCredentials = (bool)$this->getConfigValue('supportsCredentials', false);
|
||||
$maxAge = (int)$this->getConfigValue('maxAge', 0);
|
||||
$allowedOrigins = $this->getConfigValue('allowedOrigins', []);
|
||||
$allowedHeaders = $this->getConfigValue('allowedHeaders', []);
|
||||
$allowedMethods = $this->getConfigValue('allowedMethods', []);
|
||||
$exposedHeaders = $this->getConfigValue('exposedHeaders', []);
|
||||
|
||||
return compact(
|
||||
'supportsCredentials',
|
||||
'allowedOrigins',
|
||||
'allowedHeaders',
|
||||
'allowedMethods',
|
||||
'exposedHeaders',
|
||||
'maxAge'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an effective config value.
|
||||
*
|
||||
* If a filesystem config is available it takes precedence
|
||||
* over the backend settings values.
|
||||
*
|
||||
* @param $key
|
||||
* @param null $default
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getConfigValue($key, $default = null)
|
||||
{
|
||||
return $this->filesystemConfig($key) ?: $this->getValues(Settings::get($key, $default));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the filesystem config value if available.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function filesystemConfig($key)
|
||||
{
|
||||
return config('offline.cors::' . $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the repeater field values.
|
||||
*
|
||||
* @param mixed $values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getValues($values)
|
||||
{
|
||||
return \is_array($values) ? collect($values)->pluck('value')->toArray() : $values;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "offline/oc-cors-plugin",
|
||||
"description": "Setup and manage Cross-Origin Resource Sharing headers in October CMS",
|
||||
"type": "october-plugin",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Tobias Kündig",
|
||||
"email": "tobias@offline.swiss"
|
||||
}
|
||||
],
|
||||
"require": {}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?php return [
|
||||
'plugin' => [
|
||||
'name' => 'CORS',
|
||||
'description' => 'Verwalte Cross-Origin Resource Sharing Header in October CMS',
|
||||
],
|
||||
];
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?php return [
|
||||
'plugin' => [
|
||||
'name' => 'CORS',
|
||||
'description' => 'Setup and manage Cross-Origin Resource Sharing headers',
|
||||
],
|
||||
];
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace OFFLINE\CORS\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
class Settings extends Model
|
||||
{
|
||||
public $implement = ['System.Behaviors.SettingsModel'];
|
||||
public $settingsCode = 'offline_cors_settings';
|
||||
public $settingsFields = 'fields.yaml';
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
fields:
|
||||
supportsCredentials:
|
||||
label: Supports credentials
|
||||
type: switch
|
||||
comment: 'Set Access-Control-Allow-Credentials header to true'
|
||||
default: false
|
||||
span: left
|
||||
maxAge:
|
||||
label: Max age
|
||||
type: number
|
||||
comment: 'Set Access-Control-Max-Age to this value'
|
||||
default: 0
|
||||
span: right
|
||||
tabs:
|
||||
fields:
|
||||
allowedOrigins:
|
||||
label: Allowed origins
|
||||
tab: Allowed origins
|
||||
type: repeater
|
||||
span: left
|
||||
form:
|
||||
fields:
|
||||
value:
|
||||
type: text
|
||||
label: Origin
|
||||
allowedHeaders:
|
||||
label: Allowed headers
|
||||
tab: Allowed headers
|
||||
type: repeater
|
||||
span: left
|
||||
form:
|
||||
fields:
|
||||
value:
|
||||
type: text
|
||||
label: Header
|
||||
allowedMethods:
|
||||
label: Allowed methods
|
||||
tab: Allowed methods
|
||||
type: repeater
|
||||
span: left
|
||||
form:
|
||||
fields:
|
||||
value:
|
||||
type: text
|
||||
label: Method
|
||||
exposedHeaders:
|
||||
label: Exposed headers
|
||||
tab: Exposed headers
|
||||
type: repeater
|
||||
span: left
|
||||
form:
|
||||
fields:
|
||||
value:
|
||||
type: text
|
||||
label: Header
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
plugin:
|
||||
name: 'offline.cors::lang.plugin.name'
|
||||
description: 'offline.cors::lang.plugin.description'
|
||||
author: 'OFFLINE GmbH'
|
||||
icon: oc-icon-code
|
||||
homepage: ''
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
1.0.1:
|
||||
- Initial release.
|
||||
1.0.2:
|
||||
- Fixed backend settings label (thanks to LukeTowers)
|
||||
1.0.3:
|
||||
- Added support for filesystem configuration file / Added plugin to Packagist (https://packagist.org/packages/offline/oc-cors-plugin)
|
||||
1.0.4:
|
||||
- Fixed minor bug when running the plugin without custom settings
|
||||
1.0.5:
|
||||
- "Return proper 204 response code for preflight requests (thanks to @adrian-marinescu-ch on GitHub)"
|
||||
1.0.6:
|
||||
- "Dummy release to sync with Packagist version"
|
||||
1.0.7:
|
||||
- "Optimized compatibility with October v2"
|
||||
|
|
@ -27,7 +27,182 @@ class Order extends ComponentBase
|
|||
];
|
||||
}
|
||||
|
||||
public function onReportOrder()
|
||||
{
|
||||
|
||||
$currentDate = Carbon::now()->timezone('UTC +05:00');
|
||||
$currentDateFormat = $currentDate->format('Y-m-d');
|
||||
|
||||
$data = post();
|
||||
|
||||
|
||||
$orders = OrderModel::with(["client", "shipping"])
|
||||
->withCount(['order_items as order_all_amount' => function ($query) {
|
||||
$query->select(DB::raw('sum(amount)'));
|
||||
}])
|
||||
->withCount(['order_items as order_all_price' => function ($query) {
|
||||
$query->select(DB::raw('sum(price) * sum(amount)'));
|
||||
}])
|
||||
->withCount(['payment as all_payments' => function ($query) {
|
||||
$query->select(DB::raw('sum(amount)'));
|
||||
}])
|
||||
->orderBy('id', 'DESC');
|
||||
|
||||
|
||||
$start = Carbon::parse($data["start"])->format('Y-m-d');
|
||||
$end = Carbon::parse($data["end"])->format('Y-m-d');;
|
||||
|
||||
$client_id = $data["client_id"];
|
||||
$note = $data["note"];
|
||||
|
||||
|
||||
if ($client_id) {
|
||||
$orders->where("client_id", $client_id);
|
||||
}
|
||||
|
||||
if ($note) {
|
||||
$orders->where("note", "like", "%" . $note . "%");
|
||||
}
|
||||
|
||||
if ($start != $currentDateFormat){
|
||||
$orders->whereBetween('created_at', [$start, $end]);
|
||||
}
|
||||
|
||||
$ordersFiltered = $orders->get();
|
||||
|
||||
|
||||
$html_data = '';
|
||||
|
||||
for ($x = 0; $x < count($ordersFiltered); $x++) {
|
||||
$status = '';
|
||||
|
||||
$html_data .= '<tr>
|
||||
<td style="font-weight: bold;">' . ($x + 1) . '</td>
|
||||
<td><a href="/order-detail/' . $ordersFiltered[$x]->id . '" style="font-weight: bold;">Sargyt #' . $ordersFiltered[$x]->id . '</a></td>
|
||||
<td><a href="/order-detail/' . $ordersFiltered[$x]->id . '" style="font-weight: bold;">' . $ordersFiltered[$x]->client->name . '</a></td>
|
||||
<td>' . $ordersFiltered[$x]->client->country . '</td>
|
||||
<td>' . number_format($ordersFiltered[$x]->order_all_amount) . ' kg</td>
|
||||
<td><span class="badge badge-soft-primary"
|
||||
style="font-size: 14px;">' . number_format($ordersFiltered[$x]->order_all_price) . ' $</span>
|
||||
</td>
|
||||
<td><span class="badge badge-soft-success"
|
||||
style="font-size: 14px;">' . number_format($ordersFiltered[$x]->all_payments) . ' $</span>
|
||||
</td>
|
||||
<td><a href="#" class="badge badge-soft-danger" style="font-size: 14px;">' . number_format($ordersFiltered[$x]->order_all_price - $ordersFiltered[$x]->all_payments) . ' $</a>
|
||||
</td>
|
||||
<td>' . $ordersFiltered[$x]->created_at->format('d.m.Y') . '</td>
|
||||
<td>' . $ordersFiltered[$x]->note . '</td>
|
||||
|
||||
</tr>';
|
||||
}
|
||||
|
||||
if ($ordersFiltered) {
|
||||
return [
|
||||
'#orders_report_datas' => $html_data,
|
||||
|
||||
];
|
||||
} else {
|
||||
Flash::error("Yalnyshlyk bar!!");
|
||||
}
|
||||
}
|
||||
|
||||
public function onReportLogistics()
|
||||
{
|
||||
|
||||
$currentDate = Carbon::now()->timezone('UTC +05:00');
|
||||
$currentDateFormat = $currentDate->format('Y-m-d');
|
||||
|
||||
$data = post();
|
||||
|
||||
|
||||
$shippingTransports = ShippingTransportModel::with("shipping.order")->orderBy('shipping_id', 'DESC');
|
||||
|
||||
// $start = Carbon::parse($data["start"])->format('Y-m-d');
|
||||
// $end = Carbon::parse($data["end"])->format('Y-m-d');;
|
||||
|
||||
$transport = $data["transport_type"];
|
||||
$place = $data["place_now"];
|
||||
$status = $data["status"];
|
||||
$transport_no = $data["transport_no"];
|
||||
|
||||
|
||||
if ($transport) {
|
||||
$shippingTransports->where("transport_type", $transport);
|
||||
}
|
||||
|
||||
if ($place) {
|
||||
$shippingTransports->where("place_now", "like", "%" . $place . "%");
|
||||
}
|
||||
|
||||
if ($transport_no) {
|
||||
$shippingTransports->where("transport_no", "like", "%" . $transport_no . "%");
|
||||
}
|
||||
|
||||
if ($status) {
|
||||
$shippingTransports->where("status", $status);
|
||||
}
|
||||
|
||||
// if ($start != $currentDateFormat){
|
||||
// $shippingTransports->whereBetween('created_at', [$start, $end]);
|
||||
// }
|
||||
|
||||
$shippingTransportsFiltered = $shippingTransports->get();
|
||||
$shippingTransportsAmountLoaded = $shippingTransports->sum("loaded_amount");
|
||||
|
||||
|
||||
$html_data = '';
|
||||
|
||||
for ($x = 0; $x < count($shippingTransportsFiltered); $x++) {
|
||||
$status = '';
|
||||
|
||||
if($shippingTransportsFiltered[$x]->status == "loaded"){
|
||||
$status = '<span class="badge badge-soft-info"
|
||||
style="font-size: 14px;">ÝÜKLENDI</span>';
|
||||
}
|
||||
|
||||
if($shippingTransportsFiltered[$x]->status == "loading"){
|
||||
$status = '<span class="badge badge-soft-primary"
|
||||
style="font-size: 14px;">ÝÜKLENÝÄR</span>';
|
||||
}
|
||||
|
||||
if($shippingTransportsFiltered[$x]->status == "complated"){
|
||||
$status = '<span class="badge badge-soft-success"
|
||||
style="font-size: 14px;">ÝERINE ÝETIRILDI</span>';
|
||||
}
|
||||
|
||||
$html_data .= '<tr>
|
||||
<td style="font-weight: bold;">' . ($x + 1) . '</td>
|
||||
<td><a href="/order-detail/logistics/'.$shippingTransportsFiltered[$x]->shipping->order->id.'" style="font-weight: bold;">' . $shippingTransportsFiltered[$x]->transport_type . '</a></td>
|
||||
<td>' . $shippingTransportsFiltered[$x]->transport_no . '</td>
|
||||
<td><a href="/order-detail/'.$shippingTransportsFiltered[$x]->shipping->order->id.'" style="font-weight: bold;">Sargyt #'.$shippingTransportsFiltered[$x]->shipping->order->id.'</a></td>
|
||||
<td>' . $shippingTransportsFiltered[$x]->place_now . '</td>
|
||||
<td><span class="badge badge-soft-success"
|
||||
style="font-size: 14px;">' . $shippingTransportsFiltered[$x]->loaded_amount . ' kg</span>
|
||||
</td>
|
||||
<td>' . $status . '</td>
|
||||
<td>' . $shippingTransportsFiltered[$x]->note . '</td>
|
||||
</tr>';
|
||||
}
|
||||
|
||||
if ($shippingTransportsFiltered) {
|
||||
return [
|
||||
'#logistics_report_datas' => $html_data,
|
||||
'#all_amount' => ' <div class="col-md-6">
|
||||
<h3 class="card-title" style="font-size: 22px;color: #1e2038;">Logistika Boýunça Umumy</h3>
|
||||
<p class="card-title-desc" style="color: #6c6ff5;">Hasabat</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card bg-info text-white-50">
|
||||
<div class="card-body">
|
||||
<h5 class="text-white" style="text-transform: uppercase;margin-bottom: 0;"><i class="mdi mdi-bullseye-arrow me-3"></i> Ýük Mukdary: ' . number_format($shippingTransportsAmountLoaded) . ' kg</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>',
|
||||
];
|
||||
} else {
|
||||
Flash::error("Yalnyshlyk bar!!");
|
||||
}
|
||||
}
|
||||
|
||||
public function onRender()
|
||||
{
|
||||
|
|
@ -508,7 +683,7 @@ class Order extends ComponentBase
|
|||
<td><span class="badge badge-soft-success"
|
||||
style="font-size: 14px;">' . number_format($orderDatas[$x]->all_payments) . ' $</span>
|
||||
</td>
|
||||
<td><a href="#" class="badge badge-soft-danger" style="font-size: 14px;">' . number_format($orderDatas[$x]->order_all_price - $orderDatas[$x]->all_payments ) . ' $</a>
|
||||
<td><a href="#" class="badge badge-soft-danger" style="font-size: 14px;">' . number_format($orderDatas[$x]->order_all_price - $orderDatas[$x]->all_payments) . ' $</a>
|
||||
</td>
|
||||
<td>' . $orderDatas[$x]->created_at->format('d.m.Y') . '</td>
|
||||
<td>' . $orderDatas[$x]->note . '</td>
|
||||
|
|
@ -831,7 +1006,7 @@ class Order extends ComponentBase
|
|||
<td><span class="badge badge-soft-success"
|
||||
style="font-size: 14px;">' . number_format($orderDatas[$x]->all_payments) . ' $</span>
|
||||
</td>
|
||||
<td><a href="#" class="badge badge-soft-danger" style="font-size: 14px;">' . number_format($orderDatas[$x]->order_all_price - $orderDatas[$x]->all_payments ) . ' $</a>
|
||||
<td><a href="#" class="badge badge-soft-danger" style="font-size: 14px;">' . number_format($orderDatas[$x]->order_all_price - $orderDatas[$x]->all_payments) . ' $</a>
|
||||
</td>
|
||||
<td>' . $orderDatas[$x]->created_at->format('d.m.Y') . '</td>
|
||||
<td>' . $orderDatas[$x]->note . '</td>
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ class Production extends ComponentBase
|
|||
|
||||
|
||||
$productions = ProductionModel::with(['pivot_production', 'excruiter', 'shift'])->orderBy('id', 'DESC');
|
||||
$productionsCalc = ProductionModel::orderBy('id', 'DESC');
|
||||
|
||||
$start = Carbon::parse($data["start"])->format('Y-m-d');
|
||||
$end = Carbon::parse($data["end"])->format('Y-m-d');
|
||||
|
|
@ -50,23 +51,36 @@ class Production extends ComponentBase
|
|||
|
||||
if ($excruiter) {
|
||||
$productions->where("excruiter_id", $excruiter);
|
||||
$productionsCalc->where("excruiter_id", $excruiter);
|
||||
}
|
||||
|
||||
if ($shiftId) {
|
||||
$productions->where("shift_id", $shiftId);
|
||||
$productionsCalc->where("shift_id", $shiftId);
|
||||
}
|
||||
|
||||
if ($start != $currentDateFormat) {
|
||||
$productions->whereBetween('created_at', [$start, $end]);
|
||||
|
||||
$calc = $productionsCalc->select(DB::raw('MAX(all_amount) - MIN(all_amount) AS amount_subtraction'), DB::raw('MAX(all_amount) AS max_amount'), DB::raw('MIN(all_amount) AS min_amount'), DB::raw('MAX(time) AS max_time'), DB::raw('MIN(time) AS min_time'))
|
||||
->whereBetween('created_at', [$start, $end])->first();
|
||||
|
||||
$diffMinutes = Carbon::parse($calc->max_time)->diffInMinutes($calc->min_time);
|
||||
$calcTimeDiff = floor($diffMinutes / 60) . ' sagat ' . ($diffMinutes - floor($diffMinutes / 60) * 60) . ' minut';
|
||||
// dd($max);
|
||||
// $min = $productions->select(DB::raw("MIN(id)"));
|
||||
|
||||
|
||||
}
|
||||
|
||||
$productionsFiltered = $productions->get();
|
||||
|
||||
|
||||
$html_data = '';
|
||||
for ($x = 0; $x < count($productionsFiltered); $x++) {
|
||||
// dd($productionsFiltered[0]->shift->desc);
|
||||
$html_data .= '<tr>
|
||||
<td style="font-weight: bold;width: 5%;">' . ($x + 1) . '</td>
|
||||
<td style="font-weight: bold;width: 5%;">' . ($x+1) . '</td>
|
||||
<td><a href="#" style="font-weight: bold;color: #0005c5;">' . $productionsFiltered[$x]->created_at->format("d.m.Y | H:i") . '</a></td>
|
||||
<td><a href="#" style="font-weight: bold;color: #1e2038;">' . $productionsFiltered[$x]->shift->desc . '</a></td>
|
||||
<td style="text-align: center;">
|
||||
|
|
@ -80,7 +94,7 @@ class Production extends ComponentBase
|
|||
|
||||
|
||||
for ($i = 0; $i < count($productionsFiltered[$x]->pivot_production); $i++) {
|
||||
$html_data .= '<td> <a href="#">'.number_format($productionsFiltered[$x]->pivot_production[$i]->amount_percentage).'%</a></td>';
|
||||
$html_data .= '<td> <a href="#">'.number_format($productionsFiltered[$x]->pivot_production[$i]->amount_percentage).'% </a></td>';
|
||||
}
|
||||
|
||||
$html_data .= '<td style="font-weight: bold;color: #0005c5;">' . $productionsFiltered[$x]->note . '</td>
|
||||
|
|
@ -90,7 +104,26 @@ class Production extends ComponentBase
|
|||
if ($productionsFiltered) {
|
||||
return [
|
||||
'#production_report_datas' => $html_data,
|
||||
'#exampleModalFullscreenLabel' => '<font style="color: darkgreen;text-decoration: underline;font-weight: bold;">'. $startView .' - '. $endView .'</font> seneleri aralygynda güni jemi',
|
||||
// '#exampleModalFullscreenLabel' => '<font style="color: darkgreen;text-decoration: underline;font-weight: bold;">'. $startView .' - '. $endView .'</font> seneleri aralygynda güni jemi',
|
||||
'#report_dynamic' => ' <div class="col-md-4">
|
||||
<h3 class="card-title" style="font-size: 22px;color: #1e2038;">Çig Mallar Boýunça Umumy</h3>
|
||||
<p class="card-title-desc" style="color: #6c6ff5;">Hasabat</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card bg-info text-white-50">
|
||||
<div class="card-body">
|
||||
<h5 class="text-white" style="text-transform: uppercase;margin-bottom: 0;"><i class="mdi mdi-bullseye-arrow me-3"></i>Sarp Edilen Wagt: '.$calcTimeDiff.' sany</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card bg-info text-white-50">
|
||||
<div class="card-body">
|
||||
<h5 class="text-white" style="text-transform: uppercase;margin-bottom: 0;"><i class="mdi mdi-bullseye-arrow me-3"></i>Sarp Edilen Çig mal: '.number_format($calc->amount_subtraction).' kg</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
'
|
||||
];
|
||||
} else {
|
||||
Flash::error("Yalnyshlyk bar!!");
|
||||
|
|
@ -112,7 +145,17 @@ class Production extends ComponentBase
|
|||
$currentDateLast = ProductionModel::whereDate('created_at', date($currentDateFormat))->where('excruiter_id', $excruiter)->with("excruiter")->orderBy('id', 'DESC')->first();
|
||||
$currentDateFirst = ProductionModel::whereDate('created_at', date($currentDateFormat))->where('excruiter_id', $excruiter)->orderBy('id', 'ASC')->first();
|
||||
|
||||
$diffMinutes = Carbon::parse($currentDateLast->time)->diffInMinutes($currentDateFirst->time);
|
||||
$productionsCalc = ProductionModel::orderBy('id', 'DESC');
|
||||
|
||||
$calc = $productionsCalc->select(DB::raw('MAX(all_amount) - MIN(all_amount) AS amount_subtraction'), DB::raw('MAX(all_amount) AS max_amount'), DB::raw('MIN(all_amount) AS min_amount'), DB::raw('MAX(time) AS max_time'), DB::raw('MIN(time) AS min_time'))
|
||||
->whereDate('created_at', date($currentDateFormat))->where('excruiter_id', $excruiter)->first();
|
||||
|
||||
$diffMinutes = Carbon::parse($calc->max_time)->diffInMinutes($calc->min_time);
|
||||
|
||||
// $calcTimeDiff = floor($diffMinutes / 60) . ' sagat ' . ($diffMinutes - floor($diffMinutes / 60) * 60) . ' minut';
|
||||
|
||||
|
||||
// $diffMinutes = Carbon::parse($currentDateLast->time)->diffInMinutes($currentDateFirst->time);
|
||||
|
||||
$currentDateProductionAll = ProductionModel::whereDate('created_at', date($currentDateFormat))->where('excruiter_id', $excruiter)->avg('all_amount');
|
||||
|
||||
|
|
@ -135,7 +178,7 @@ class Production extends ComponentBase
|
|||
)
|
||||
);
|
||||
|
||||
$producedAll = $currentDateLast->all_amount - $currentDateFirst->all_amount;
|
||||
$producedAll = $calc->amount_subtraction;
|
||||
|
||||
$countDailyChanges = ProductionModel::whereDate('created_at', date($currentDateFormat))->where('excruiter_id', $excruiter)->get();
|
||||
|
||||
|
|
@ -220,17 +263,31 @@ class Production extends ComponentBase
|
|||
$currentDateExcruiters = ProductionModel::whereDate('created_at', date($currentDateFormat))->groupBy("excruiter_id")->orderBy('id', 'DESC')->with("excruiter")->get();
|
||||
|
||||
|
||||
|
||||
for ($i = 0; $i < count($currentDateExcruiters); $i++) {
|
||||
|
||||
$currentDateLastExc = ProductionModel::whereDate('created_at', date($currentDateFormat))->where('excruiter_id', $currentDateExcruiters[$i]->excruiter_id)->orderBy('id', 'DESC')->first();
|
||||
|
||||
$currentDateFirstExc = ProductionModel::whereDate('created_at', date($currentDateFormat))->where('excruiter_id', $currentDateExcruiters[$i]->excruiter_id)->orderBy('id', 'ASC')->first();
|
||||
// $currentDateFirstExc = ProductionModel::whereDate('created_at', date($currentDateFormat))->where('excruiter_id', $currentDateExcruiters[$i]->excruiter_id)->orderBy('id', 'ASC')->first();
|
||||
|
||||
$diffMinutesExc = Carbon::parse($currentDateLastExc->time)->diffInMinutes($currentDateFirstExc->time);
|
||||
/////////////
|
||||
|
||||
|
||||
$productionsCalc = ProductionModel::orderBy('id', 'DESC');
|
||||
|
||||
$calc = $productionsCalc->select(DB::raw('MAX(all_amount) - MIN(all_amount) AS amount_subtraction'), DB::raw('MAX(all_amount) AS max_amount'), DB::raw('MIN(all_amount) AS min_amount'), DB::raw('MAX(time) AS max_time'), DB::raw('MIN(time) AS min_time'))
|
||||
->whereDate('created_at', date($currentDateFormat))->where('excruiter_id', $currentDateExcruiters[$i]->excruiter_id)->first();
|
||||
|
||||
$diffMinutesExc = Carbon::parse($calc->max_time)->diffInMinutes($calc->min_time);
|
||||
|
||||
|
||||
/////////////
|
||||
|
||||
// $diffMinutesExc = Carbon::parse($currentDateLastExc->time)->diffInMinutes($currentDateFirstExc->time);
|
||||
|
||||
$hourCountExc = floor($diffMinutesExc / 60) . ' sagat ' . ($diffMinutesExc - floor($diffMinutesExc / 60) * 60) . ' minut';
|
||||
|
||||
$allAmountExc = $currentDateLastExc->all_amount - $currentDateFirstExc->all_amount;
|
||||
$allAmountExc = $calc->amount_subtraction;
|
||||
|
||||
// dd($currentDateFirstExc);
|
||||
$html_data3 .= '<div class="row">';
|
||||
|
|
@ -272,13 +329,21 @@ class Production extends ComponentBase
|
|||
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$currentDateShifts = ProductionModel::whereDate('created_at', date($currentDateFormat))
|
||||
->where("excruiter_id", $excruiter)
|
||||
// ->where("excruiter_id", $excruiter)
|
||||
->with(["shift", "excruiter", "pivot_production"])
|
||||
->orderBy('id', 'ASC')
|
||||
->groupBy("shift_id")
|
||||
->groupBy("shift_id", "excruiter_id")
|
||||
// ->max("id")
|
||||
->orderBy('excruiter_id', 'DESC')
|
||||
// ->distinct()
|
||||
->get();
|
||||
|
||||
// dd($currentDateShifts);
|
||||
// $products = ProductModel::where("report", "simple")->get();
|
||||
|
||||
|
||||
|
|
@ -296,9 +361,9 @@ class Production extends ComponentBase
|
|||
<th>Wagty</th>
|
||||
<th>Jemi</th>
|
||||
';
|
||||
for ($ii = 0; $ii < count($currentDateShifts[0]->pivot_production); $ii++) {
|
||||
$html_data4 .= '<th>' . $currentDateShifts[0]->pivot_production[$ii]->product_name . '</th>';
|
||||
}
|
||||
// for ($ii = 0; $ii < count($currentDateShifts[0]->pivot_production); $ii++) {
|
||||
// $html_data4 .= '<th>' . $currentDateShifts[0]->pivot_production[$ii]->product_name . '</th>';
|
||||
// }
|
||||
$html_data4 .= '</tr>
|
||||
</thead><tbody>';
|
||||
|
||||
|
|
@ -306,40 +371,38 @@ class Production extends ComponentBase
|
|||
|
||||
for ($i = 0; $i < count($currentDateShifts); $i++) {
|
||||
|
||||
$pivotShiftLasts = PivotProductionModel::where('production_id', $currentDateShifts[$i]->id)->get();
|
||||
$productionsCalc = ProductionModel::orderBy('id', 'DESC')->whereDate('created_at', date($currentDateFormat));
|
||||
|
||||
$currentDateLastShift = ProductionModel::whereDate('created_at', date($currentDateFormat))->where('shift_id', $currentDateShifts[$i]->shift_id)->where('excruiter_id', $currentDateShifts[$i]->excruiter_id)->with('excruiter')->orderBy('id', 'DESC')->first();
|
||||
$calc = $productionsCalc->select(DB::raw('MAX(all_amount) - MIN(all_amount) AS amount_subtraction'), DB::raw('MAX(all_amount) AS max_amount'), DB::raw('MIN(all_amount) AS min_amount'), DB::raw('MAX(time) AS max_time'), DB::raw('MIN(time) AS min_time'))
|
||||
->where('shift_id', $currentDateShifts[$i]->shift_id)->where('excruiter_id', $currentDateShifts[$i]->excruiter_id)->first();
|
||||
|
||||
$currentDateFirstShift = ProductionModel::whereDate('created_at', date($currentDateFormat))->where('shift_id', $currentDateShifts[$i]->shift_id)->where('excruiter_id', $currentDateShifts[$i]->excruiter_id)->orderBy('id', 'ASC')->first();
|
||||
$diffMinutes = Carbon::parse($calc->max_time)->diffInMinutes($calc->min_time);
|
||||
|
||||
$diffMinutesShift = Carbon::parse($currentDateLastShift->time)->diffInMinutes($currentDateFirstShift->time);
|
||||
|
||||
$hourCountShift = floor($diffMinutesShift / 60) . ' sagat ' . ($diffMinutesShift - floor($diffMinutesShift / 60) * 60) . ' minut';
|
||||
|
||||
$hourCountShiftCalc = floor($diffMinutesShift / 60) . '.' . ($diffMinutesShift - floor($diffMinutesShift / 60) * 60);
|
||||
|
||||
$allAmountShift = $currentDateLastShift->all_amount - $currentDateFirstShift->all_amount;
|
||||
$hourCountShift = floor($diffMinutes / 60) . ' sagat ' . ($diffMinutes - floor($diffMinutes / 60) * 60) . ' minut';
|
||||
|
||||
$html_data4 .= '<tr>
|
||||
<th scope="row">' . ($i + 1) . '</th>
|
||||
<td style="font-weight: bold;color: #0005c5;">' . $currentDateShifts[$i]->shift->desc . '(' . $currentDateShifts[$i]->shift->start . ' - ' . $currentDateShifts[$i]->shift->end . ')</td>
|
||||
<td><span class="badge badge-soft-info"
|
||||
style="font-size: 14px;">' . $currentDateLastShift->excruiter->name . '</span></td>
|
||||
<td>' . $hourCountShift . '</td>
|
||||
<td>' . $allAmountShift . ' kg</td>';
|
||||
style="font-size: 14px;">' . $currentDateShifts[$i]->excruiter->name . '</span></td>
|
||||
<td>'.$hourCountShift.'</td>
|
||||
<td>'.$calc->amount_subtraction.' kg</td>';
|
||||
|
||||
|
||||
for ($x = 0; $x < count($pivotShiftLasts); $x++) {
|
||||
// for ($x = 0; $x < count($pivotShiftLasts); $x++) {
|
||||
|
||||
$calculatedPercentageShift = (float) ($pivotShiftLasts[$x]->amount_percentage / 100) * (float) $allAmountShift;
|
||||
// $calculatedPercentageShift = (float) ($pivotShiftLasts[$x]->amount_percentage / 100) * (float) $allAmountShift;
|
||||
|
||||
$html_data4 .= '<td>' . ($calculatedPercentageShift) . ' kg </td>';
|
||||
}
|
||||
// $html_data4 .= '<td>' . ($calculatedPercentageShift) . ' kg </td>';
|
||||
// }
|
||||
|
||||
|
||||
$html_data4 .= '</tr>';
|
||||
}
|
||||
|
||||
$html_data4 .= ' <tr>
|
||||
|
||||
</tr>';
|
||||
$html_data4 .= ' </tbody>
|
||||
</table></div></div></div>';
|
||||
|
||||
|
|
|
|||
|
|
@ -2,5 +2,144 @@ title = "orders/report"
|
|||
url = "/orders/report"
|
||||
layout = "platform_main"
|
||||
is_hidden = 0
|
||||
|
||||
[order]
|
||||
==
|
||||
list order
|
||||
<?php
|
||||
function onStart(){
|
||||
$this["clients"] = Romanah\Gokbakja\Models\Client::get();
|
||||
}
|
||||
?>
|
||||
==
|
||||
{% put styles %}
|
||||
<link href="{{'assets/libs/datatables.net-bs4/css/dataTables.bootstrap4.min.css'|theme}}" rel="stylesheet"
|
||||
type="text/css" />
|
||||
<link href="{{'assets/libs/datatables.net-buttons-bs4/css/buttons.bootstrap4.min.css'|theme}}" rel="stylesheet"
|
||||
type="text/css" />
|
||||
<link href="{{'assets/libs/datatables.net-select-bs4/css/select.bootstrap4.min.css'|theme}}" rel="stylesheet"
|
||||
type="text/css" />
|
||||
|
||||
<link href="{{'assets/libs/select2/css/select2.min.css'|theme}}" rel="stylesheet" type="text/css">
|
||||
{% endput %}
|
||||
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form data-request="onReportOrder" data-request-flash>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div>
|
||||
<label class="form-label">Seneleri Saýlaň</label>
|
||||
|
||||
<div class="input-daterange input-group" id="datepicker6"
|
||||
data-date-format="d.m.yyyy" data-date-autoclose="true" data-provide="datepicker"
|
||||
data-date-container='#datepicker6'>
|
||||
<input type="text" class="form-control" name="start"
|
||||
placeholder="Başlanýan sene" />
|
||||
<input type="text" class="form-control" name="end"
|
||||
placeholder="Gutarýan sene" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="form-label">Klent Saýlaň</label>
|
||||
<select class="form-control select2" name="client_id">
|
||||
<option value="0">Saýla</option>
|
||||
{% for client in clients %}
|
||||
<option value="{{client.id}}">{{client.name}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<label class="form-label">Bellik</label>
|
||||
<input name="note" class="form-control" placeholder="Bellik">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col">
|
||||
<button type="submit" class="btn btn-primary waves-effect waves-light"
|
||||
style="margin-top: 30px;width: 100%;">Hasabat</button>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row" id="all_amount">
|
||||
<div class="col-md-6">
|
||||
<h3 class="card-title" style="font-size: 22px;color: #1e2038;">Sargytlar Boýunça Umumy</h3>
|
||||
<p class="card-title-desc" style="color: #6c6ff5;">Hasabat</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<table id="datatable-buttons" class="table table-striped table-bordered dt-responsive nowrap"
|
||||
style="border-collapse: collapse; border-spacing: 0; width: 100%;" data-page-length='13'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 5%;">№</th>
|
||||
<th>Sargyt No</th>
|
||||
<th>Klent</th>
|
||||
<th>Ýurdy</th>
|
||||
<th>Mukdary</th>
|
||||
<th>Bahasy</th>
|
||||
<th>Tölenen</th>
|
||||
<th>Bergisi</th>
|
||||
<th>Senesi</th>
|
||||
<th>Bellik</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="orders_report_datas">
|
||||
|
||||
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th style="width: 5%;">№</th>
|
||||
<th>Sargyt No</th>
|
||||
<th>Klent</th>
|
||||
<th>Ýurdy</th>
|
||||
<th>Mukdary</th>
|
||||
<th>Bahasy</th>
|
||||
<th>Tölenen</th>
|
||||
<th>Bergisi</th>
|
||||
<th>Senesi</th>
|
||||
<th>Bellik</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% partial 'dataTableJs' %}
|
||||
{% put scripts %}
|
||||
<script src="{{'assets/libs/bootstrap-datepicker/js/bootstrap-datepicker.min.js'|theme}}"></script>
|
||||
<script src="{{'assets/libs/select2/js/select2.min.js'|theme}}"></script>
|
||||
<script src="{{'assets/js/pages/form-advanced.init.js'|theme}}"></script>
|
||||
{% endput %}
|
||||
|
|
|
|||
|
|
@ -2,5 +2,153 @@ title = "orders/shipping"
|
|||
url = "/orders/shipping"
|
||||
layout = "platform_main"
|
||||
is_hidden = 0
|
||||
|
||||
[order]
|
||||
==
|
||||
shipping order
|
||||
<?php
|
||||
function onStart(){
|
||||
|
||||
}
|
||||
?>
|
||||
==
|
||||
{% put styles %}
|
||||
<link href="{{'assets/libs/datatables.net-bs4/css/dataTables.bootstrap4.min.css'|theme}}" rel="stylesheet"
|
||||
type="text/css" />
|
||||
<link href="{{'assets/libs/datatables.net-buttons-bs4/css/buttons.bootstrap4.min.css'|theme}}" rel="stylesheet"
|
||||
type="text/css" />
|
||||
<link href="{{'assets/libs/datatables.net-select-bs4/css/select.bootstrap4.min.css'|theme}}" rel="stylesheet"
|
||||
type="text/css" />
|
||||
|
||||
<link href="{{'assets/libs/select2/css/select2.min.css'|theme}}" rel="stylesheet" type="text/css">
|
||||
{% endput %}
|
||||
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form data-request="onReportLogistics" data-request-flash>
|
||||
<div class="row">
|
||||
<!-- <div class="col">
|
||||
<div>
|
||||
<label class="form-label">Seneleri Saýlaň</label>
|
||||
|
||||
<div class="input-daterange input-group" id="datepicker6"
|
||||
data-date-format="d.m.yyyy" data-date-autoclose="true" data-provide="datepicker"
|
||||
data-date-container='#datepicker6'>
|
||||
<input type="text" class="form-control" name="start"
|
||||
placeholder="Başlanýan sene" />
|
||||
<input type="text" class="form-control" name="end"
|
||||
placeholder="Gutarýan sene" />
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="col">
|
||||
<label class="form-label">Transport Saýlaň</label>
|
||||
<select class="form-control select2" name="transport_type">
|
||||
<option value="0">Saýla</option>
|
||||
<option value="truck">Tyr</option>
|
||||
<option value="train">Wagon</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<label class="form-label">Ýer ýazyň</label>
|
||||
<input name="place_now" class="form-control" placeholder="Ýer ýazyň">
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<label class="form-label">Transport No</label>
|
||||
<input name="transport_no" class="form-control" placeholder="Transport Nomeri">
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<label class="form-label">Status</label>
|
||||
<select class="form-control select2" name="status">
|
||||
<option value="0">Saýla</option>
|
||||
<option value="loading">Ýüklenýär</option>
|
||||
<option value="loaded">Ýüklendi</option>
|
||||
<option value="complated">Ýerine Ýetirildi</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button type="submit" class="btn btn-primary waves-effect waves-light"
|
||||
style="margin-top: 30px;width: 100%;">Hasabat</button>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row" id="all_amount">
|
||||
<div class="col-md-6">
|
||||
<h3 class="card-title" style="font-size: 22px;color: #1e2038;">Logistika Boýunça Umumy</h3>
|
||||
<p class="card-title-desc" style="color: #6c6ff5;">Hasabat</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<table id="datatable-buttons" class="table table-striped table-bordered dt-responsive nowrap"
|
||||
style="border-collapse: collapse; border-spacing: 0; width: 100%;" data-page-length='13'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 5%;">№</th>
|
||||
<th>Transport</th>
|
||||
<th>Transport No</th>
|
||||
<th>Sargyt No</th>
|
||||
<th>Ýüki</th>
|
||||
<th>Şu Wagtky Ýeri</th>
|
||||
<th>Status</th>
|
||||
<th>Bellik</th>
|
||||
<!-- <th>Настройки</th> -->
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="logistics_report_datas">
|
||||
|
||||
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th style="width: 5%;">№</th>
|
||||
<th>Transport</th>
|
||||
<th>Transport No</th>
|
||||
<th>Sargyt No</th>
|
||||
<th>Ýüki</th>
|
||||
<th>Şu Wagtky Ýeri</th>
|
||||
<th>Status</th>
|
||||
<th>Bellik</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% partial 'dataTableJs' %}
|
||||
{% put scripts %}
|
||||
<script src="{{'assets/libs/bootstrap-datepicker/js/bootstrap-datepicker.min.js'|theme}}"></script>
|
||||
<script src="{{'assets/libs/select2/js/select2.min.js'|theme}}"></script>
|
||||
<script src="{{'assets/js/pages/form-advanced.init.js'|theme}}"></script>
|
||||
{% endput %}
|
||||
|
|
|
|||
|
|
@ -99,21 +99,20 @@ function onStart(){
|
|||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h3 class="card-title" style="font-size: 22px;color: #1e2038;">Çig Mallar Boýunça Umumy</h3>
|
||||
<p class="card-title-desc" style="color: #6c6ff5;">Hasabat</p>
|
||||
</div>
|
||||
<div class="col-md-6" style="text-align: right;">
|
||||
<div class="row" id="report_dynamic">
|
||||
|
||||
<!-- <div class="col-md-6" style="text-align: right;">
|
||||
<button type="button" class="btn btn-primary waves-effect waves-light"
|
||||
data-bs-toggle="modal" data-bs-target="#exampleModalFullscreen">
|
||||
<i class="ri-pie-chart-line align-middle ms-2" style="font-size: 17px;"></i> Jemini Jemle
|
||||
</button>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
{% partial "production/modal-report" %}
|
||||
|
||||
<!-- <h1 id="calcq">qqq</h1>
|
||||
<h1 id="timeDif">qqq</h1> -->
|
||||
<table id="datatable-buttons" class="table table-striped table-bordered dt-responsive nowrap"
|
||||
style="border-collapse: collapse; border-spacing: 0; width: 100%;" data-page-length='13'>
|
||||
<thead>
|
||||
|
|
|
|||
|
|
@ -42,12 +42,7 @@
|
|||
<!-- Tab panes -->
|
||||
<div class="tab-content p-3 text-muted">
|
||||
<div class="tab-pane active" id="home1" role="tabpanel">
|
||||
<div id="calculation_of_day">
|
||||
|
||||
</div>
|
||||
<hr>
|
||||
<div id="avg_of_day">
|
||||
|
||||
<div id="report_dynamic">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue