Merge branch 'master' of https://github.com/brkcvn/akaunting into new-plans
This commit is contained in:
commit
fa23598ee4
@ -150,7 +150,7 @@ abstract class Report
|
||||
|
||||
public function applySearchStringFilter($event)
|
||||
{
|
||||
$input = request('search');
|
||||
$input = request('search', '');
|
||||
|
||||
// Remove year as it's handled based on financial start
|
||||
$search_year = 'year:' . $this->getSearchStringValue('year', '', $input);
|
||||
|
@ -17,7 +17,7 @@ abstract class Widget
|
||||
public $default_name = '';
|
||||
|
||||
public $default_settings = [
|
||||
'width' => 'w-full lg:w-2/4 px-12 my-8',
|
||||
'width' => 'w-full lg:w-2/4 lg:px-12 my-8',
|
||||
];
|
||||
|
||||
public $description = '';
|
||||
|
@ -48,6 +48,20 @@ class Handler extends ExceptionHandler
|
||||
'password_confirmation',
|
||||
];
|
||||
|
||||
/**
|
||||
* Register the exception handling callbacks for the application.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->reportable(function (Throwable $e) {
|
||||
if (config('logging.default') == 'bugsnag') {
|
||||
call_user_func(config('bugsnag.before_send'), $e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Report or log an exception.
|
||||
*
|
||||
|
29
app/Exceptions/Trackers/Bugsnag.php
Normal file
29
app/Exceptions/Trackers/Bugsnag.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions\Trackers;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class Bugsnag
|
||||
{
|
||||
public static function beforeSend(Throwable $e): void
|
||||
{
|
||||
app('bugsnag')->setAppVersion(version('short'));
|
||||
|
||||
app('bugsnag')->registerCallback(function ($report) {
|
||||
$report->setMetaData([
|
||||
'akaunting' => [
|
||||
'company_id' => (string) company_id(),
|
||||
'locale' => (string) app()->getLocale(),
|
||||
'timezone' => (string) config('app.timezone'),
|
||||
'route_name' => (string) static::getRouteName(),
|
||||
]
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
public static function getRouteName(): ?string
|
||||
{
|
||||
return request()->route()?->getName();
|
||||
}
|
||||
}
|
76
app/Exceptions/Trackers/Sentry.php
Normal file
76
app/Exceptions/Trackers/Sentry.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions\Trackers;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Sentry\Event;
|
||||
use Sentry\EventHint;
|
||||
use Sentry\Tracing\SamplingContext;
|
||||
|
||||
class Sentry
|
||||
{
|
||||
public static function beforeSend(Event $event, ?EventHint $hint): ?Event
|
||||
{
|
||||
$event->setRelease(version('short'));
|
||||
|
||||
$event->setTags([
|
||||
'company_id' => (string) company_id(),
|
||||
'locale' => (string) app()->getLocale(),
|
||||
'timezone' => (string) config('app.timezone'),
|
||||
'app_type' => (string) static::getAppType(),
|
||||
'route_name' => (string) static::getRouteName(),
|
||||
]);
|
||||
|
||||
return $event;
|
||||
}
|
||||
|
||||
public static function tracesSampler(SamplingContext $context): float
|
||||
{
|
||||
if (static::shouldFilterAgent()) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return config('sentry.traces_sample_rate');
|
||||
}
|
||||
|
||||
public static function shouldFilterAgent(): bool
|
||||
{
|
||||
$user_agent = request()->userAgent();
|
||||
|
||||
$filter_agents = explode(',', env('SENTRY_TRACES_FILTER_AGENTS'));
|
||||
|
||||
foreach ($filter_agents as $filter_agent) {
|
||||
if (! Str::contains($user_agent, $filter_agent)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function getAppType(): string
|
||||
{
|
||||
$hostname = gethostname();
|
||||
|
||||
if (Str::contains($hostname, '-queue-')) {
|
||||
$app_type = 'queue';
|
||||
} elseif (Str::contains($hostname, '-cron-')) {
|
||||
$app_type = 'cron';
|
||||
} elseif (request()->isApi()) {
|
||||
$app_type = 'api';
|
||||
} elseif (app()->runningInConsole()) {
|
||||
$app_type = 'console';
|
||||
} else {
|
||||
$app_type = 'ui';
|
||||
}
|
||||
|
||||
return $app_type;
|
||||
}
|
||||
|
||||
public static function getRouteName(): ?string
|
||||
{
|
||||
return request()->route()?->getName();
|
||||
}
|
||||
}
|
@ -195,7 +195,7 @@ class Categories extends Controller
|
||||
|
||||
flash($message)->success();
|
||||
} else {
|
||||
$response['redirect'] = route('categories.edit', $category_id);
|
||||
$response['redirect'] = route('categories.edit', $category->id);
|
||||
|
||||
$message = $response['message'];
|
||||
|
||||
|
@ -8,16 +8,24 @@ use App\Interfaces\Job\HasSource;
|
||||
use App\Interfaces\Job\ShouldCreate;
|
||||
use App\Models\Banking\Reconciliation;
|
||||
use App\Models\Banking\Transaction;
|
||||
use App\Utilities\Date;
|
||||
|
||||
class CreateReconciliation extends Job implements HasOwner, HasSource, ShouldCreate
|
||||
{
|
||||
public function handle(): Reconciliation
|
||||
{
|
||||
\DB::transaction(function () {
|
||||
$started_at = Date::parse($this->request->get('started_at'))->startOfDay();
|
||||
$ended_at = Date::parse($this->request->get('ended_at'))->endOfDay();
|
||||
|
||||
$reconcile = (int) $this->request->get('reconcile');
|
||||
$transactions = $this->request->get('transactions');
|
||||
|
||||
$this->request->merge(['reconciled' => $reconcile]);
|
||||
$this->request->merge([
|
||||
'started_at' => $started_at,
|
||||
'ended_at' => $ended_at,
|
||||
'reconciled' => $reconcile,
|
||||
]);
|
||||
|
||||
$this->model = Reconciliation::create($this->request->all());
|
||||
|
||||
|
@ -18,7 +18,7 @@ class Reconciliation extends Model
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['company_id', 'account_id', 'started_at', 'ended_at', 'closing_balance', 'reconciled', 'created_from', 'created_by'];
|
||||
protected $fillable = ['company_id', 'account_id', 'started_at', 'ended_at', 'closing_balance', 'transactions', 'reconciled', 'created_from', 'created_by'];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
|
@ -565,7 +565,7 @@ class Transaction extends Model
|
||||
'permission' => 'read-banking-transactions',
|
||||
'attributes' => [
|
||||
'id' => 'index-line-actions-send-email-' . $this->type . '-' . $this->id,
|
||||
'@click' => 'onEmail("' . route('modals.transactions.emails.create', $this->id) . '")',
|
||||
'@click' => 'onSendEmail("' . route('modals.transactions.emails.create', $this->id) . '")',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
@ -488,6 +488,20 @@ class Document extends Model
|
||||
return $actions;
|
||||
}
|
||||
|
||||
if (app('mobile-detect')->isMobile()) {
|
||||
try {
|
||||
$actions[] = [
|
||||
'title' => trans('general.show'),
|
||||
'icon' => 'visibility',
|
||||
'url' => route($prefix . '.show', $this->id),
|
||||
'permission' => 'read-' . $group . '-' . $permission_prefix,
|
||||
'attributes' => [
|
||||
'id' => 'index-more-actions-show-' . $this->id,
|
||||
],
|
||||
];
|
||||
} catch (\Exception $e) {}
|
||||
}
|
||||
|
||||
try {
|
||||
if (! $this->reconciled) {
|
||||
$actions[] = [
|
||||
@ -524,7 +538,7 @@ class Document extends Model
|
||||
'permission' => 'read-' . $group . '-' . $permission_prefix,
|
||||
'attributes' => [
|
||||
'id' => 'index-line-actions-payment-' . $this->type . '-' . $this->id,
|
||||
'@click' => 'onPayment("' . $this->id . '")',
|
||||
'@click' => 'onAddPayment("' . route('modals.documents.document.transactions.create', $this->id) . '")',
|
||||
],
|
||||
];
|
||||
} catch (\Exception $e) {}
|
||||
@ -601,7 +615,7 @@ class Document extends Model
|
||||
'permission' => 'read-' . $group . '-' . $permission_prefix,
|
||||
'attributes' => [
|
||||
'id' => 'index-line-actions-send-email-' . $this->type . '-' . $this->id,
|
||||
'@click' => 'onEmail("' . route('modals.'. $prefix . '.emails.create', $this->id) . '")',
|
||||
'@click' => 'onSendEmail("' . route('modals.'. $prefix . '.emails.create', $this->id) . '")',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
@ -106,6 +106,11 @@ trait Charts
|
||||
$percent_position = $position ?: setting('localisation.percent_position');
|
||||
|
||||
switch ($type) {
|
||||
case 'integer':
|
||||
$label = new Raw("function(value) {
|
||||
return value
|
||||
}");
|
||||
break;
|
||||
case 'percent':
|
||||
$label = new Raw("function(value) {
|
||||
" . ($percent_position == 'right' ? "return value + '%';" : "return '%' + value;") . "
|
||||
|
@ -8,16 +8,12 @@ trait SearchString
|
||||
* Get the value of a name in search string
|
||||
* Example: search=type:customer year:2020 account_id:20
|
||||
* Example: issued_at>=2021-02-01 issued_at<=2021-02-10 account_id:49
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
public function getSearchStringValue($name, $default = '', $input = null)
|
||||
public function getSearchStringValue(string $name, string $default = '', string $input = ''): string|array
|
||||
{
|
||||
$value = $default;
|
||||
|
||||
if (is_null($input)) {
|
||||
$input = request('search');
|
||||
}
|
||||
$input = $input ?: request('search', '');
|
||||
|
||||
// $manager = $this->getSearchStringManager();
|
||||
// $parsed = $manager->parse($input);
|
||||
@ -30,14 +26,14 @@ trait SearchString
|
||||
if (empty($variable[0]) || ($variable[0] != $name) || empty($variable[1])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (strpos($column, ':')) {
|
||||
$value = $variable[1];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!is_array($value)) {
|
||||
if (! is_array($value)) {
|
||||
$value = [];
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ class CashFlow extends Widget
|
||||
public $default_name = 'widgets.cash_flow';
|
||||
|
||||
public $default_settings = [
|
||||
'width' => 'w-full my-8 px-12',
|
||||
'width' => 'w-full my-8 lg:px-12',
|
||||
];
|
||||
|
||||
public $description = 'widgets.description.cash_flow';
|
||||
|
@ -44,6 +44,7 @@
|
||||
"barryvdh/laravel-dompdf": "^2.0",
|
||||
"barryvdh/laravel-ide-helper": "^2.9",
|
||||
"bkwld/cloner": "^3.10",
|
||||
"bugsnag/bugsnag-laravel": "^2.24",
|
||||
"doctrine/dbal": "^3.1",
|
||||
"fruitcake/laravel-cors": "^2.0",
|
||||
"genealabs/laravel-model-caching": "0.12.*",
|
||||
@ -67,6 +68,7 @@
|
||||
"plank/laravel-mediable": "^5.4",
|
||||
"riverskies/laravel-mobile-detect": "^1.3",
|
||||
"santigarcor/laratrust": "^7.0",
|
||||
"sentry/sentry-laravel": "^3.0",
|
||||
"simple-icons/simple-icons": "^6.0",
|
||||
"simshaun/recurr": "^5.0",
|
||||
"staudenmeir/belongs-to-through": "^2.12",
|
||||
|
1083
composer.lock
generated
1083
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -180,6 +180,7 @@ return [
|
||||
/*
|
||||
* Package Service Providers...
|
||||
*/
|
||||
Bugsnag\BugsnagLaravel\BugsnagServiceProvider::class,
|
||||
Laravel\Tinker\TinkerServiceProvider::class,
|
||||
|
||||
/*
|
||||
|
364
config/bugsnag.php
Normal file
364
config/bugsnag.php
Normal file
@ -0,0 +1,364 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| API Key
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| You can find your API key on your Bugsnag dashboard.
|
||||
|
|
||||
| This api key points the Bugsnag notifier to the project in your account
|
||||
| which should receive your application's uncaught exceptions.
|
||||
|
|
||||
*/
|
||||
|
||||
'api_key' => env('BUGSNAG_API_KEY', ''),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| App Type
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Set the type of application executing the current code.
|
||||
|
|
||||
*/
|
||||
|
||||
'app_type' => env('BUGSNAG_APP_TYPE'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| App Version
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Set the version of application executing the current code.
|
||||
|
|
||||
*/
|
||||
|
||||
'app_version' => env('BUGSNAG_APP_VERSION'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Batch Sending
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Set to true to send the errors through to Bugsnag when the PHP process
|
||||
| shuts down, in order to prevent your app waiting on HTTP requests.
|
||||
|
|
||||
| Setting this to false will send an HTTP request straight away for each
|
||||
| error.
|
||||
|
|
||||
*/
|
||||
|
||||
'batch_sending' => env('BUGSNAG_BATCH_SENDING', true),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Endpoint
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Set what server the Bugsnag notifier should send errors to. By default
|
||||
| this is set to 'https://notify.bugsnag.com', but for Bugsnag Enterprise
|
||||
| this should be the URL to your Bugsnag instance.
|
||||
|
|
||||
*/
|
||||
|
||||
'endpoint' => env('BUGSNAG_ENDPOINT'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Filters
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Use this if you want to ensure you don't send sensitive data such as
|
||||
| passwords, and credit card numbers to our servers. Any keys which
|
||||
| contain these strings will be filtered.
|
||||
|
|
||||
| This option has been deprecated in favour of 'redacted_keys'
|
||||
|
|
||||
*/
|
||||
|
||||
'filters' => empty(env('BUGSNAG_FILTERS')) ? null : explode(',', str_replace(' ', '', env('BUGSNAG_FILTERS'))),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Hostname
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| You can set the hostname of your server to something specific for you to
|
||||
| identify it by if needed.
|
||||
|
|
||||
*/
|
||||
|
||||
'hostname' => env('BUGSNAG_HOSTNAME', env('APP_URL')),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Proxy
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is where you can set the proxy settings you'd like us to use when
|
||||
| communicating with Bugsnag when reporting errors.
|
||||
|
|
||||
*/
|
||||
|
||||
'proxy' => array_filter([
|
||||
'http' => env('HTTP_PROXY'),
|
||||
'https' => env('HTTPS_PROXY'),
|
||||
'no' => empty(env('NO_PROXY')) ? null : explode(',', str_replace(' ', '', env('NO_PROXY'))),
|
||||
]),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Project Root
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Bugsnag marks stacktrace lines as in-project if they come from files
|
||||
| inside your “project root”. You can set this here.
|
||||
|
|
||||
| If this is not set, we will automatically try to detect it.
|
||||
|
|
||||
*/
|
||||
|
||||
'project_root' => env('BUGSNAG_PROJECT_ROOT'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Project Root Regex
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Bugsnag marks stacktrace lines as in-project if they come from files
|
||||
| inside your “project root”. You can set this here.
|
||||
|
|
||||
| This option allows you to set it as a regular expression and will take
|
||||
| precedence over "project_root" if both are defined.
|
||||
|
|
||||
*/
|
||||
|
||||
'project_root_regex' => env('BUGSNAG_PROJECT_ROOT_REGEX'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Strip Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The strip path is a path to be trimmed from the start of any filepaths in
|
||||
| your stacktraces.
|
||||
|
|
||||
| If this is not set, we will automatically try to detect it.
|
||||
|
|
||||
*/
|
||||
|
||||
'strip_path' => env('BUGSNAG_STRIP_PATH'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Strip Path Regex
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The strip path is a path to be trimmed from the start of any filepaths in
|
||||
| your stacktraces.
|
||||
|
|
||||
| This option allows you to set it as a regular expression and will take
|
||||
| precedence over "strip_path" if both are defined.
|
||||
|
|
||||
*/
|
||||
|
||||
'strip_path_regex' => env('BUGSNAG_STRIP_PATH_REGEX'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Query
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Enable this if you'd like us to automatically record all queries executed
|
||||
| as breadcrumbs.
|
||||
|
|
||||
*/
|
||||
|
||||
'query' => env('BUGSNAG_QUERY', true),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Bindings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Enable this if you'd like us to include the query bindings in our query
|
||||
| breadcrumbs.
|
||||
|
|
||||
*/
|
||||
|
||||
'bindings' => env('BUGSNAG_QUERY_BINDINGS', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Release Stage
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Set the release stage to use when sending notifications to Bugsnag.
|
||||
|
|
||||
| Leaving this unset will default to using the application environment.
|
||||
|
|
||||
*/
|
||||
|
||||
'release_stage' => env('BUGSNAG_RELEASE_STAGE'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Notify Release Stages
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Set which release stages should send notifications to Bugsnag.
|
||||
|
|
||||
*/
|
||||
|
||||
'notify_release_stages' => empty(env('BUGSNAG_NOTIFY_RELEASE_STAGES')) ? null : explode(',', str_replace(' ', '', env('BUGSNAG_NOTIFY_RELEASE_STAGES'))),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Send Code
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Bugsnag automatically sends a small snippet of the code that crashed to
|
||||
| help you diagnose even faster from within your dashboard. If you don’t
|
||||
| want to send this snippet, then set this to false.
|
||||
|
|
||||
*/
|
||||
|
||||
'send_code' => env('BUGSNAG_SEND_CODE', true),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Callbacks
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Enable this if you'd like us to enable our default set of notification
|
||||
| callbacks. These add things like the cookie information and session
|
||||
| details to the error to be sent to Bugsnag.
|
||||
|
|
||||
| If you'd like to add your own callbacks, you can call the
|
||||
| Bugsnag::registerCallback method from the boot method of your app
|
||||
| service provider.
|
||||
|
|
||||
*/
|
||||
|
||||
'callbacks' => env('BUGSNAG_CALLBACKS', true),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| User
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Enable this if you'd like us to set the current user logged in via
|
||||
| Laravel's authentication system.
|
||||
|
|
||||
| If you'd like to add your own user resolver, you can do this by using
|
||||
| callbacks via Bugsnag::registerCallback.
|
||||
|
|
||||
*/
|
||||
|
||||
'user' => env('BUGSNAG_USER', true),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Logger Notify Level
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This sets the level at which a logged message will trigger a notification
|
||||
| to Bugsnag. By default this level will be 'notice'.
|
||||
|
|
||||
| Must be one of the Psr\Log\LogLevel levels from the Psr specification.
|
||||
|
|
||||
*/
|
||||
|
||||
'logger_notify_level' => env('BUGSNAG_LOGGER_LEVEL'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Auto Capture Sessions
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Enable this to start tracking sessions and deliver them to Bugsnag.
|
||||
|
|
||||
*/
|
||||
|
||||
'auto_capture_sessions' => env('BUGSNAG_CAPTURE_SESSIONS', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Sessions Endpoint
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Sets a url to send tracked sessions to.
|
||||
|
|
||||
*/
|
||||
|
||||
'session_endpoint' => env('BUGSNAG_SESSION_ENDPOINT'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Builds Endpoint
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Sets a url to send build reports to.
|
||||
|
|
||||
*/
|
||||
|
||||
'build_endpoint' => env('BUGSNAG_BUILD_ENDPOINT'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Discard Classes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| An array of classes that should not be sent to Bugsnag.
|
||||
|
|
||||
| This can contain both fully qualified class names and regular expressions.
|
||||
|
|
||||
*/
|
||||
|
||||
'discard_classes' => empty(env('BUGSNAG_DISCARD_CLASSES')) ? null : explode(',', env('BUGSNAG_DISCARD_CLASSES')),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Redacted Keys
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| An array of metadata keys that should be redacted.
|
||||
|
|
||||
*/
|
||||
|
||||
'redacted_keys' => empty(env('BUGSNAG_REDACTED_KEYS')) ? null : explode(',', env('BUGSNAG_REDACTED_KEYS')),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Feature flags
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| An array of feature flags to add to all reports.
|
||||
|
|
||||
| Each element in the array must have a "name" key and can optionally have a
|
||||
| "variant" key, for example:
|
||||
|
|
||||
| [
|
||||
| ['name' => 'example without a variant'],
|
||||
| ['name' => 'example with a variant', 'variant' => 'example of a variant'],
|
||||
| ]
|
||||
|
|
||||
*/
|
||||
|
||||
'feature_flags' => [],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Before send
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| An array of callback class and method.
|
||||
|
|
||||
*/
|
||||
|
||||
'before_send' => [env('BUGSNAG_BEFORE_SEND_CLASS', 'App\\Exceptions\\Trackers\\Bugsnag'), 'beforeSend'],
|
||||
|
||||
];
|
@ -128,6 +128,16 @@ return [
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
],
|
||||
|
||||
'bugsnag' => [
|
||||
'driver' => 'bugsnag',
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
],
|
||||
|
||||
'sentry' => [
|
||||
'driver' => 'sentry',
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
|
59
config/sentry.php
Normal file
59
config/sentry.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'dsn' => env('SENTRY_LARAVEL_DSN', env('SENTRY_DSN')),
|
||||
|
||||
// capture release as git sha
|
||||
// 'release' => trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||
|
||||
// When left empty or `null` the Laravel environment will be used
|
||||
'environment' => env('SENTRY_ENVIRONMENT'),
|
||||
|
||||
'breadcrumbs' => [
|
||||
// Capture Laravel logs in breadcrumbs
|
||||
'logs' => true,
|
||||
|
||||
// Capture SQL queries in breadcrumbs
|
||||
'sql_queries' => true,
|
||||
|
||||
// Capture bindings on SQL queries logged in breadcrumbs
|
||||
'sql_bindings' => true,
|
||||
|
||||
// Capture queue job information in breadcrumbs
|
||||
'queue_info' => true,
|
||||
|
||||
// Capture command information in breadcrumbs
|
||||
'command_info' => true,
|
||||
],
|
||||
|
||||
'tracing' => [
|
||||
// Trace queue jobs as their own transactions
|
||||
'queue_job_transactions' => env('SENTRY_TRACE_QUEUE_ENABLED', false),
|
||||
|
||||
// Capture queue jobs as spans when executed on the sync driver
|
||||
'queue_jobs' => true,
|
||||
|
||||
// Capture SQL queries as spans
|
||||
'sql_queries' => true,
|
||||
|
||||
// Try to find out where the SQL query originated from and add it to the query spans
|
||||
'sql_origin' => true,
|
||||
|
||||
// Capture views as spans
|
||||
'views' => true,
|
||||
|
||||
// Indicates if the tracing integrations supplied by Sentry should be loaded
|
||||
'default_integrations' => true,
|
||||
],
|
||||
|
||||
// @see: https://docs.sentry.io/platforms/php/configuration/options/#send-default-pii
|
||||
'send_default_pii' => env('SENTRY_SEND_DEFAULT_PII', true),
|
||||
|
||||
'traces_sample_rate' => (float)(env('SENTRY_TRACES_SAMPLE_RATE', 0.0)),
|
||||
|
||||
'before_send' => [env('SENTRY_BEFORE_SEND_CLASS', 'App\\Exceptions\\Trackers\\Sentry'), 'beforeSend'],
|
||||
|
||||
'traces_sampler' => [env('SENTRY_TRACES_SAMPLER_CLASS', 'App\\Exceptions\\Trackers\\Sentry'), 'tracesSampler'],
|
||||
|
||||
];
|
54
public/css/app.css
vendored
54
public/css/app.css
vendored
@ -51260,6 +51260,12 @@ body{
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
[dir="rtl"] .rtl\:-scale-x-100{
|
||||
--tw-scale-x: -1;
|
||||
-webkit-transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
[dir="rtl"] .rtl\:space-x-reverse > :not([hidden]) ~ :not([hidden]){
|
||||
--tw-space-x-reverse: 1;
|
||||
}
|
||||
@ -51788,9 +51794,15 @@ body{
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
.lg\:my-16{
|
||||
margin-top: 4rem;
|
||||
margin-bottom: 4rem;
|
||||
=======
|
||||
.lg\:-mx-12{
|
||||
margin-left: -3rem;
|
||||
margin-right: -3rem;
|
||||
>>>>>>> d1b81891f887f0ababe1c40221defa5b69162795
|
||||
}
|
||||
|
||||
.lg\:my-0{
|
||||
@ -51864,6 +51876,10 @@ body{
|
||||
height: 16rem;
|
||||
}
|
||||
|
||||
.lg\:h-auto{
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.lg\:h-48{
|
||||
height: 12rem;
|
||||
}
|
||||
@ -51880,16 +51896,17 @@ body{
|
||||
height: 3rem;
|
||||
}
|
||||
|
||||
.lg\:h-auto{
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.lg\:w-9{
|
||||
width: 2.25rem;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
.lg\:w-18{
|
||||
width: 4.5rem;
|
||||
=======
|
||||
.lg\:w-96{
|
||||
width: 24rem;
|
||||
>>>>>>> d1b81891f887f0ababe1c40221defa5b69162795
|
||||
}
|
||||
|
||||
.lg\:w-1\/2{
|
||||
@ -51972,10 +51989,6 @@ body{
|
||||
width: 1rem;
|
||||
}
|
||||
|
||||
.lg\:w-96{
|
||||
width: 24rem;
|
||||
}
|
||||
|
||||
.lg\:w-2\/4{
|
||||
width: 50%;
|
||||
}
|
||||
@ -52099,6 +52112,26 @@ body{
|
||||
border-right-width: 1px;
|
||||
}
|
||||
|
||||
.lg\:px-3{
|
||||
padding-left: 0.75rem;
|
||||
padding-right: 0.75rem;
|
||||
}
|
||||
|
||||
.lg\:px-4{
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.lg\:px-6{
|
||||
padding-left: 1.5rem;
|
||||
padding-right: 1.5rem;
|
||||
}
|
||||
|
||||
.lg\:px-12{
|
||||
padding-left: 3rem;
|
||||
padding-right: 3rem;
|
||||
}
|
||||
|
||||
.lg\:px-24{
|
||||
padding-left: 6rem;
|
||||
padding-right: 6rem;
|
||||
@ -52109,11 +52142,6 @@ body{
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
.lg\:px-12{
|
||||
padding-left: 3rem;
|
||||
padding-right: 3rem;
|
||||
}
|
||||
|
||||
.lg\:pl-24{
|
||||
padding-left: 6rem;
|
||||
}
|
||||
|
@ -189,8 +189,10 @@ export default {
|
||||
let el = this.$refs.dropdownMenu;
|
||||
let target = event.target;
|
||||
|
||||
if (el !== target && ! el.contains(target)) {
|
||||
this.isOpen = false;
|
||||
if (typeof el != "undefined") {
|
||||
if (el !== target && ! el.contains(target)) {
|
||||
this.isOpen = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
@ -52,13 +52,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div v-else class="document-contact-with-contact-bill-to">
|
||||
<div>
|
||||
<span class="text-sm">{{ contactInfoText }}</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="overflow-x-visible mt-0">
|
||||
<table class="table table-borderless p-0">
|
||||
<tbody>
|
||||
@ -88,28 +86,26 @@
|
||||
<th class="font-normal text-xs text-left p-0">
|
||||
{{ contact.phone }}
|
||||
<span v-if="contact.email">
|
||||
- {{ contact.email }}
|
||||
- {{ contact.email }}
|
||||
</span>
|
||||
</th>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="absolute flex flex-col mt-2">
|
||||
<button type="button" class="p-0 text-xs text-purple ltr:text-left rtl:text-right" @click="onContactEdit">
|
||||
<span class="bg-no-repeat bg-0-2 bg-0-full hover:bg-full-2 bg-gradient-to-b from-transparent to-purple transition-backgroundSize">
|
||||
{{ editContactText.replace(':contact_name', contact.name).replace(':field', contact.name) }}
|
||||
</span>
|
||||
</button>
|
||||
<button type="button" class="p-0 text-xs text-purple ltr:text-left rtl:text-right" @click="onContactList">
|
||||
<span class="bg-no-repeat bg-0-2 bg-0-full hover:bg-full-2 bg-gradient-to-b from-transparent to-purple transition-backgroundSize">
|
||||
{{ chooseDifferentContactText }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div :class="show.contact_selected ? 'flex' : 'hidden'" class="absolute flex-col mt-2">
|
||||
<button type="button" class="p-0 text-xs text-purple ltr:text-left rtl:text-right" @click="onContactEdit">
|
||||
<span class="bg-no-repeat bg-0-2 bg-0-full hover:bg-full-2 bg-gradient-to-b from-transparent to-purple transition-backgroundSize">
|
||||
{{ editContactText.replace(':contact_name', contact.name).replace(':field', contact.name) }}
|
||||
</span>
|
||||
</button>
|
||||
<button type="button" class="p-0 text-xs text-purple ltr:text-left rtl:text-right" @click="onContactList">
|
||||
<span class="bg-no-repeat bg-0-2 bg-0-full hover:bg-full-2 bg-gradient-to-b from-transparent to-purple transition-backgroundSize">
|
||||
{{ chooseDifferentContactText }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<component v-bind:is="add_new_html" @submit="onSubmit" @cancel="onCancel"></component>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -303,8 +303,8 @@ export default {
|
||||
|
||||
onInput(evt) {
|
||||
this.search = evt.target.value;
|
||||
|
||||
let option_url = this.selected_options[this.filter_index].url;
|
||||
|
||||
let option_url = this.selected_options.length > 0 ? this.selected_options[this.filter_index].url : '';
|
||||
|
||||
if (this.search) {
|
||||
if (option_url.indexOf('?') === -1) {
|
||||
@ -581,7 +581,7 @@ export default {
|
||||
|
||||
onFilterDelete(index) {
|
||||
this.show_icon = true;
|
||||
this.show_close_icon = false;
|
||||
|
||||
this.filter_list.push(this.selected_options[index]);
|
||||
|
||||
if (this.filter_last_step == 'options') {
|
||||
@ -598,8 +598,10 @@ export default {
|
||||
|
||||
if (this.filter_index == 0) {
|
||||
this.onChangeSearchAndFilterText(this.defaultPlaceholder, true);
|
||||
this.show_close_icon = false;
|
||||
} else {
|
||||
this.show_icon = false;
|
||||
this.show_close_icon = true;
|
||||
}
|
||||
|
||||
this.filter_last_step = 'options';
|
||||
@ -790,6 +792,10 @@ export default {
|
||||
if (this.filter_index > 0) {
|
||||
this.onChangeSearchAndFilterText(this.enterPlaceholder, false);
|
||||
}
|
||||
|
||||
if (this.selected_values.length > 0) {
|
||||
this.show_close_icon = true;
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
@ -875,7 +875,7 @@ export default {
|
||||
if (this.multiple) {
|
||||
this.selected = [];
|
||||
} else {
|
||||
this.selected = null;
|
||||
this.selected = '';
|
||||
}
|
||||
|
||||
return;
|
||||
@ -892,7 +892,7 @@ export default {
|
||||
}, this);
|
||||
} else {
|
||||
if (! options.find((option) => option == this.selected)) {
|
||||
this.selected = null;
|
||||
this.selected = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1094,7 +1094,7 @@ export default {
|
||||
if (this.multiple) {
|
||||
this.selected = [];
|
||||
} else {
|
||||
this.selected = null;
|
||||
this.selected = '';
|
||||
}
|
||||
|
||||
return;
|
||||
@ -1111,7 +1111,7 @@ export default {
|
||||
}, this);
|
||||
} else {
|
||||
if (! options.find((option) => option == this.selected)) {
|
||||
this.selected = null;
|
||||
this.selected = '';
|
||||
}
|
||||
}
|
||||
},
|
||||
|
393
resources/assets/js/mixins/global.js
vendored
393
resources/assets/js/mixins/global.js
vendored
@ -229,6 +229,9 @@ export default {
|
||||
// Bulk Action modal cancel
|
||||
onCancelBulkAction() {
|
||||
this.bulk_action.modal = false;
|
||||
|
||||
let documentClasses = document.body.classList;
|
||||
documentClasses.remove('overflow-y-hidden', 'overflow-overlay', '-ml-4');
|
||||
},
|
||||
|
||||
// Bulk Action Clear selected items
|
||||
@ -583,6 +586,396 @@ export default {
|
||||
this.onChangeCurrency(currency_code);
|
||||
},
|
||||
|
||||
async onAddPayment(url) {
|
||||
let payment = {
|
||||
modal: false,
|
||||
url: url,
|
||||
title: '',
|
||||
html: '',
|
||||
buttons:{}
|
||||
};
|
||||
|
||||
let payment_promise = Promise.resolve(window.axios.get(payment.url));
|
||||
|
||||
payment_promise.then(response => {
|
||||
payment.modal = true;
|
||||
payment.title = response.data.data.title;
|
||||
payment.html = response.data.html;
|
||||
payment.buttons = response.data.data.buttons;
|
||||
|
||||
this.component = Vue.component('add-new-component', (resolve, reject) => {
|
||||
resolve({
|
||||
template: '<div id="dynamic-payment-component"><akaunting-modal-add-new modal-dialog-class="max-w-md" modal-position-top :show="payment.modal" @submit="onSubmit" @cancel="onCancel" :buttons="payment.buttons" :title="payment.title" :is_component=true :message="payment.html"></akaunting-modal-add-new></div>',
|
||||
|
||||
components: {
|
||||
AkauntingDropzoneFileUpload,
|
||||
AkauntingContactCard,
|
||||
AkauntingCompanyEdit,
|
||||
AkauntingEditItemColumns,
|
||||
AkauntingItemButton,
|
||||
AkauntingDocumentButton,
|
||||
AkauntingSearch,
|
||||
AkauntingRadioGroup,
|
||||
AkauntingSelect,
|
||||
AkauntingSelectRemote,
|
||||
AkauntingMoney,
|
||||
AkauntingModal,
|
||||
AkauntingModalAddNew,
|
||||
AkauntingDate,
|
||||
AkauntingRecurring,
|
||||
AkauntingHtmlEditor,
|
||||
AkauntingCountdown,
|
||||
AkauntingCurrencyConversion,
|
||||
AkauntingConnectTransactions,
|
||||
AkauntingSwitch,
|
||||
AkauntingSlider,
|
||||
AkauntingColor,
|
||||
CardForm,
|
||||
[Select.name]: Select,
|
||||
[Option.name]: Option,
|
||||
[Steps.name]: Steps,
|
||||
[Step.name]: Step,
|
||||
[Button.name]: Button,
|
||||
[Link.name]: Link,
|
||||
[Tooltip.name]: Tooltip,
|
||||
[ColorPicker.name]: ColorPicker,
|
||||
},
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
form:{},
|
||||
payment: payment,
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onSubmit(event) {
|
||||
this.form = event;
|
||||
|
||||
this.form.response = {};
|
||||
|
||||
this.loading = true;
|
||||
|
||||
let data = this.form.data();
|
||||
|
||||
FormData.prototype.appendRecursive = function(data, wrapper = null) {
|
||||
for(var name in data) {
|
||||
if (wrapper) {
|
||||
if ((typeof data[name] == 'object' || data[name].constructor === Array) && ((data[name] instanceof File != true ) && (data[name] instanceof Blob != true))) {
|
||||
this.appendRecursive(data[name], wrapper + '[' + name + ']');
|
||||
} else {
|
||||
this.append(wrapper + '[' + name + ']', data[name]);
|
||||
}
|
||||
} else {
|
||||
if ((typeof data[name] == 'object' || data[name].constructor === Array) && ((data[name] instanceof File != true ) && (data[name] instanceof Blob != true))) {
|
||||
this.appendRecursive(data[name], name);
|
||||
} else {
|
||||
this.append(name, data[name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let form_data = new FormData();
|
||||
form_data.appendRecursive(data);
|
||||
|
||||
window.axios({
|
||||
method: this.form.method,
|
||||
url: this.form.action,
|
||||
data: form_data,
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': window.Laravel.csrfToken,
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
if (response.data.success) {
|
||||
if (response.data.redirect) {
|
||||
this.form.loading = true;
|
||||
|
||||
window.location.href = response.data.redirect;
|
||||
}
|
||||
}
|
||||
|
||||
if (response.data.error) {
|
||||
this.form.loading = false;
|
||||
|
||||
this.form.response = response.data;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.form.loading = false;
|
||||
|
||||
this.form.onFail(error);
|
||||
|
||||
this.method_show_html = error.message;
|
||||
});
|
||||
},
|
||||
|
||||
onCancel() {
|
||||
this.payment.modal = false;
|
||||
this.payment.html = null;
|
||||
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove('overflow-y-hidden', 'overflow-overlay', '-ml-4');
|
||||
},
|
||||
}
|
||||
})
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
})
|
||||
.finally(function () {
|
||||
// always executed
|
||||
});
|
||||
},
|
||||
|
||||
async onEditPayment(url) {
|
||||
let payment = {
|
||||
modal: false,
|
||||
url: url,
|
||||
title: '',
|
||||
html: '',
|
||||
buttons:{}
|
||||
};
|
||||
|
||||
let payment_promise = Promise.resolve(window.axios.get(payment.url));
|
||||
|
||||
payment_promise.then(response => {
|
||||
payment.modal = true;
|
||||
payment.title = response.data.data.title;
|
||||
payment.html = response.data.html;
|
||||
payment.buttons = response.data.data.buttons;
|
||||
|
||||
this.component = Vue.component('add-new-component', (resolve, reject) => {
|
||||
resolve({
|
||||
template: '<div id="dynamic-payment-component"><akaunting-modal-add-new modal-dialog-class="max-w-md" modal-position-top :show="payment.modal" @submit="onSubmit" @cancel="onCancel" :buttons="payment.buttons" :title="payment.title" :is_component=true :message="payment.html"></akaunting-modal-add-new></div>',
|
||||
|
||||
components: {
|
||||
AkauntingDropzoneFileUpload,
|
||||
AkauntingContactCard,
|
||||
AkauntingCompanyEdit,
|
||||
AkauntingEditItemColumns,
|
||||
AkauntingItemButton,
|
||||
AkauntingDocumentButton,
|
||||
AkauntingSearch,
|
||||
AkauntingRadioGroup,
|
||||
AkauntingSelect,
|
||||
AkauntingSelectRemote,
|
||||
AkauntingMoney,
|
||||
AkauntingModal,
|
||||
AkauntingModalAddNew,
|
||||
AkauntingDate,
|
||||
AkauntingRecurring,
|
||||
AkauntingHtmlEditor,
|
||||
AkauntingCountdown,
|
||||
AkauntingCurrencyConversion,
|
||||
AkauntingConnectTransactions,
|
||||
AkauntingSwitch,
|
||||
AkauntingSlider,
|
||||
AkauntingColor,
|
||||
CardForm,
|
||||
[Select.name]: Select,
|
||||
[Option.name]: Option,
|
||||
[Steps.name]: Steps,
|
||||
[Step.name]: Step,
|
||||
[Button.name]: Button,
|
||||
[Link.name]: Link,
|
||||
[Tooltip.name]: Tooltip,
|
||||
[ColorPicker.name]: ColorPicker,
|
||||
},
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
form:{},
|
||||
payment: payment,
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onSubmit(event) {
|
||||
this.form = event;
|
||||
|
||||
this.form.response = {};
|
||||
|
||||
this.loading = true;
|
||||
|
||||
let data = this.form.data();
|
||||
|
||||
FormData.prototype.appendRecursive = function(data, wrapper = null) {
|
||||
for(var name in data) {
|
||||
if (wrapper) {
|
||||
if ((typeof data[name] == 'object' || data[name].constructor === Array) && ((data[name] instanceof File != true ) && (data[name] instanceof Blob != true))) {
|
||||
this.appendRecursive(data[name], wrapper + '[' + name + ']');
|
||||
} else {
|
||||
this.append(wrapper + '[' + name + ']', data[name]);
|
||||
}
|
||||
} else {
|
||||
if ((typeof data[name] == 'object' || data[name].constructor === Array) && ((data[name] instanceof File != true ) && (data[name] instanceof Blob != true))) {
|
||||
this.appendRecursive(data[name], name);
|
||||
} else {
|
||||
this.append(name, data[name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let form_data = new FormData();
|
||||
form_data.appendRecursive(data);
|
||||
|
||||
window.axios({
|
||||
method: this.form.method,
|
||||
url: this.form.action,
|
||||
data: form_data,
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': window.Laravel.csrfToken,
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
if (response.data.success) {
|
||||
if (response.data.redirect) {
|
||||
this.form.loading = true;
|
||||
|
||||
window.location.href = response.data.redirect;
|
||||
}
|
||||
}
|
||||
|
||||
if (response.data.error) {
|
||||
this.form.loading = false;
|
||||
|
||||
this.form.response = response.data;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.form.loading = false;
|
||||
|
||||
this.form.onFail(error);
|
||||
|
||||
this.method_show_html = error.message;
|
||||
});
|
||||
},
|
||||
|
||||
onCancel() {
|
||||
this.payment.modal = false;
|
||||
this.payment.html = null;
|
||||
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove('overflow-y-hidden', 'overflow-overlay', '-ml-4');
|
||||
},
|
||||
}
|
||||
})
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
})
|
||||
.finally(function () {
|
||||
// always executed
|
||||
});
|
||||
},
|
||||
|
||||
async onSendEmail(url) {
|
||||
let email = {
|
||||
modal: false,
|
||||
url: url,
|
||||
title: '',
|
||||
html: '',
|
||||
buttons:{}
|
||||
};
|
||||
|
||||
let email_promise = Promise.resolve(window.axios.get(email.url));
|
||||
|
||||
if (this.email_template) {
|
||||
email_promise = Promise.resolve(window.axios.get(email.url, {
|
||||
params: {
|
||||
email_template: this.email_template
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
this.email_template = false;
|
||||
|
||||
email_promise.then(response => {
|
||||
email.modal = true;
|
||||
email.title = response.data.data.title;
|
||||
email.html = response.data.html;
|
||||
email.buttons = response.data.data.buttons;
|
||||
|
||||
this.component = Vue.component('add-new-component', (resolve, reject) => {
|
||||
resolve({
|
||||
template: '<div id="dynamic-email-component"><akaunting-modal-add-new modal-dialog-class="max-w-screen-md" :show="email.modal" @submit="onSubmit" @cancel="onCancel" :buttons="email.buttons" :title="email.title" :is_component=true :message="email.html"></akaunting-modal-add-new></div>',
|
||||
|
||||
components: {
|
||||
AkauntingDropzoneFileUpload,
|
||||
AkauntingContactCard,
|
||||
AkauntingCompanyEdit,
|
||||
AkauntingEditItemColumns,
|
||||
AkauntingItemButton,
|
||||
AkauntingDocumentButton,
|
||||
AkauntingSearch,
|
||||
AkauntingRadioGroup,
|
||||
AkauntingSelect,
|
||||
AkauntingSelectRemote,
|
||||
AkauntingMoney,
|
||||
AkauntingModal,
|
||||
AkauntingModalAddNew,
|
||||
AkauntingDate,
|
||||
AkauntingRecurring,
|
||||
AkauntingHtmlEditor,
|
||||
AkauntingCountdown,
|
||||
AkauntingCurrencyConversion,
|
||||
AkauntingConnectTransactions,
|
||||
AkauntingSwitch,
|
||||
AkauntingSlider,
|
||||
AkauntingColor,
|
||||
CardForm,
|
||||
[Select.name]: Select,
|
||||
[Option.name]: Option,
|
||||
[Steps.name]: Steps,
|
||||
[Step.name]: Step,
|
||||
[Button.name]: Button,
|
||||
[Link.name]: Link,
|
||||
[Tooltip.name]: Tooltip,
|
||||
[ColorPicker.name]: ColorPicker,
|
||||
},
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
form:{},
|
||||
email: email,
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onSubmit(event) {
|
||||
this.$emit('submit', event);
|
||||
|
||||
event.submit();
|
||||
},
|
||||
|
||||
onCancel() {
|
||||
this.email.modal = false;
|
||||
this.email.html = null;
|
||||
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove('overflow-y-hidden', 'overflow-overlay', '-ml-4');
|
||||
},
|
||||
}
|
||||
})
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
})
|
||||
.finally(function () {
|
||||
// always executed
|
||||
});
|
||||
},
|
||||
|
||||
onShareLink(url) {
|
||||
let share = {
|
||||
modal: false,
|
||||
|
4
resources/assets/js/plugins/form.js
vendored
4
resources/assets/js/plugins/form.js
vendored
@ -493,7 +493,9 @@ export default class Form {
|
||||
|
||||
// Form fields check validation issue
|
||||
onFail(error) {
|
||||
this.errors.record(error.response.data.errors);
|
||||
if (typeof this.errors != "undefined") {
|
||||
this.errors.record(error.response.data.errors);
|
||||
}
|
||||
|
||||
this.loading = false;
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ const app = new Vue({
|
||||
}
|
||||
},
|
||||
|
||||
methods:{
|
||||
methods: {
|
||||
setDueMinDate(date) {
|
||||
this.min_due_date = date;
|
||||
},
|
||||
|
@ -33,62 +33,6 @@ const app = new Vue({
|
||||
},
|
||||
|
||||
methods: {
|
||||
async onEmail(route) {
|
||||
let email = {
|
||||
modal: false,
|
||||
route: route,
|
||||
title: '',
|
||||
html: '',
|
||||
buttons:{}
|
||||
};
|
||||
|
||||
let email_promise = Promise.resolve(window.axios.get(email.route));
|
||||
|
||||
email_promise.then(response => {
|
||||
email.modal = true;
|
||||
email.title = response.data.data.title;
|
||||
email.html = response.data.html;
|
||||
email.buttons = response.data.data.buttons;
|
||||
|
||||
this.component = Vue.component('add-new-component', (resolve, reject) => {
|
||||
resolve({
|
||||
template: '<div id="dynamic-email-component"><akaunting-modal-add-new modal-dialog-class="max-w-md" :show="email.modal" @submit="onSubmit" @cancel="onCancel" :buttons="email.buttons" :title="email.title" :is_component=true :message="email.html"></akaunting-modal-add-new></div>',
|
||||
|
||||
mixins: [
|
||||
Global
|
||||
],
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
form:{},
|
||||
email: email,
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onSubmit(event) {
|
||||
this.$emit('submit', event);
|
||||
|
||||
event.submit();
|
||||
},
|
||||
|
||||
onCancel() {
|
||||
this.email.modal = false;
|
||||
this.email.html = null;
|
||||
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove('overflow-y-hidden', 'overflow-overlay', '-ml-4');
|
||||
},
|
||||
}
|
||||
})
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
})
|
||||
.finally(function () {
|
||||
// always executed
|
||||
});
|
||||
},
|
||||
//
|
||||
},
|
||||
});
|
||||
|
309
resources/assets/js/views/common/documents.js
vendored
309
resources/assets/js/views/common/documents.js
vendored
@ -589,315 +589,10 @@ const app = new Vue({
|
||||
this.form.items[item_index][field_name] = this.items[item_index][field_name];
|
||||
},
|
||||
|
||||
async onPayment(document_id) {
|
||||
if (typeof document_id == 'object') {
|
||||
document_id = document.getElementById('document_id').value;
|
||||
}
|
||||
|
||||
let payment = {
|
||||
modal: false,
|
||||
url: url + '/modals/documents/' + document_id + '/transactions/create',
|
||||
title: '',
|
||||
html: '',
|
||||
buttons:{}
|
||||
};
|
||||
|
||||
let payment_promise = Promise.resolve(window.axios.get(payment.url));
|
||||
|
||||
payment_promise.then(response => {
|
||||
payment.modal = true;
|
||||
payment.title = response.data.data.title;
|
||||
payment.html = response.data.html;
|
||||
payment.buttons = response.data.data.buttons;
|
||||
|
||||
this.component = Vue.component('add-new-component', (resolve, reject) => {
|
||||
resolve({
|
||||
template: '<div id="dynamic-payment-component"><akaunting-modal-add-new modal-dialog-class="max-w-md" modal-position-top :show="payment.modal" @submit="onSubmit" @cancel="onCancel" :buttons="payment.buttons" :title="payment.title" :is_component=true :message="payment.html"></akaunting-modal-add-new></div>',
|
||||
|
||||
mixins: [
|
||||
Global
|
||||
],
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
form:{},
|
||||
payment: payment,
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onSubmit(event) {
|
||||
this.form = event;
|
||||
|
||||
this.form.response = {};
|
||||
|
||||
this.loading = true;
|
||||
|
||||
let data = this.form.data();
|
||||
|
||||
FormData.prototype.appendRecursive = function(data, wrapper = null) {
|
||||
for(var name in data) {
|
||||
if (wrapper) {
|
||||
if ((typeof data[name] == 'object' || data[name].constructor === Array) && ((data[name] instanceof File != true ) && (data[name] instanceof Blob != true))) {
|
||||
this.appendRecursive(data[name], wrapper + '[' + name + ']');
|
||||
} else {
|
||||
this.append(wrapper + '[' + name + ']', data[name]);
|
||||
}
|
||||
} else {
|
||||
if ((typeof data[name] == 'object' || data[name].constructor === Array) && ((data[name] instanceof File != true ) && (data[name] instanceof Blob != true))) {
|
||||
this.appendRecursive(data[name], name);
|
||||
} else {
|
||||
this.append(name, data[name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let form_data = new FormData();
|
||||
form_data.appendRecursive(data);
|
||||
|
||||
window.axios({
|
||||
method: this.form.method,
|
||||
url: this.form.action,
|
||||
data: form_data,
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': window.Laravel.csrfToken,
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
if (response.data.success) {
|
||||
if (response.data.redirect) {
|
||||
this.form.loading = true;
|
||||
|
||||
window.location.href = response.data.redirect;
|
||||
}
|
||||
}
|
||||
|
||||
if (response.data.error) {
|
||||
this.form.loading = false;
|
||||
|
||||
this.form.response = response.data;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.form.loading = false;
|
||||
|
||||
this.form.onFail(error);
|
||||
|
||||
this.method_show_html = error.message;
|
||||
});
|
||||
},
|
||||
|
||||
onCancel() {
|
||||
this.payment.modal = false;
|
||||
this.payment.html = null;
|
||||
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove('overflow-y-hidden', 'overflow-overlay', '-ml-4');
|
||||
},
|
||||
}
|
||||
})
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
})
|
||||
.finally(function () {
|
||||
// always executed
|
||||
});
|
||||
},
|
||||
|
||||
async onEditPayment(transaction_id) {
|
||||
let document_id = document.getElementById('document_id').value;
|
||||
|
||||
let payment = {
|
||||
modal: false,
|
||||
url: url + '/modals/documents/' + document_id + '/transactions/' + transaction_id + '/edit',
|
||||
title: '',
|
||||
html: '',
|
||||
buttons:{}
|
||||
};
|
||||
|
||||
let payment_promise = Promise.resolve(window.axios.get(payment.url));
|
||||
|
||||
payment_promise.then(response => {
|
||||
payment.modal = true;
|
||||
payment.title = response.data.data.title;
|
||||
payment.html = response.data.html;
|
||||
payment.buttons = response.data.data.buttons;
|
||||
|
||||
this.component = Vue.component('add-new-component', (resolve, reject) => {
|
||||
resolve({
|
||||
template: '<div id="dynamic-payment-component"><akaunting-modal-add-new modal-dialog-class="max-w-md" modal-position-top :show="payment.modal" @submit="onSubmit" @cancel="onCancel" :buttons="payment.buttons" :title="payment.title" :is_component=true :message="payment.html"></akaunting-modal-add-new></div>',
|
||||
|
||||
mixins: [
|
||||
Global
|
||||
],
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
form:{},
|
||||
payment: payment,
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onSubmit(event) {
|
||||
this.form = event;
|
||||
|
||||
this.form.response = {};
|
||||
|
||||
this.loading = true;
|
||||
|
||||
let data = this.form.data();
|
||||
|
||||
FormData.prototype.appendRecursive = function(data, wrapper = null) {
|
||||
for(var name in data) {
|
||||
if (wrapper) {
|
||||
if ((typeof data[name] == 'object' || data[name].constructor === Array) && ((data[name] instanceof File != true ) && (data[name] instanceof Blob != true))) {
|
||||
this.appendRecursive(data[name], wrapper + '[' + name + ']');
|
||||
} else {
|
||||
this.append(wrapper + '[' + name + ']', data[name]);
|
||||
}
|
||||
} else {
|
||||
if ((typeof data[name] == 'object' || data[name].constructor === Array) && ((data[name] instanceof File != true ) && (data[name] instanceof Blob != true))) {
|
||||
this.appendRecursive(data[name], name);
|
||||
} else {
|
||||
this.append(name, data[name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let form_data = new FormData();
|
||||
form_data.appendRecursive(data);
|
||||
|
||||
window.axios({
|
||||
method: this.form.method,
|
||||
url: this.form.action,
|
||||
data: form_data,
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': window.Laravel.csrfToken,
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
if (response.data.success) {
|
||||
if (response.data.redirect) {
|
||||
this.form.loading = true;
|
||||
|
||||
window.location.href = response.data.redirect;
|
||||
}
|
||||
}
|
||||
|
||||
if (response.data.error) {
|
||||
this.form.loading = false;
|
||||
|
||||
this.form.response = response.data;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.form.loading = false;
|
||||
|
||||
this.form.onFail(error);
|
||||
|
||||
this.method_show_html = error.message;
|
||||
});
|
||||
},
|
||||
|
||||
onCancel() {
|
||||
this.payment.modal = false;
|
||||
this.payment.html = null;
|
||||
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove('overflow-y-hidden', 'overflow-overlay', '-ml-4');
|
||||
},
|
||||
}
|
||||
})
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
})
|
||||
.finally(function () {
|
||||
// always executed
|
||||
});
|
||||
},
|
||||
|
||||
async onEmail(route) {
|
||||
let email = {
|
||||
modal: false,
|
||||
route: route,
|
||||
title: '',
|
||||
html: '',
|
||||
buttons:{}
|
||||
};
|
||||
|
||||
let email_promise = Promise.resolve(window.axios.get(email.route));
|
||||
|
||||
if (this.email_template) {
|
||||
email_promise = Promise.resolve(window.axios.get(email.route, {
|
||||
params: {
|
||||
email_template: this.email_template
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
this.email_template = false;
|
||||
|
||||
email_promise.then(response => {
|
||||
email.modal = true;
|
||||
email.title = response.data.data.title;
|
||||
email.html = response.data.html;
|
||||
email.buttons = response.data.data.buttons;
|
||||
|
||||
this.component = Vue.component('add-new-component', (resolve, reject) => {
|
||||
resolve({
|
||||
template: '<div id="dynamic-email-component"><akaunting-modal-add-new modal-dialog-class="max-w-md" :show="email.modal" @submit="onSubmit" @cancel="onCancel" :buttons="email.buttons" :title="email.title" :is_component=true :message="email.html"></akaunting-modal-add-new></div>',
|
||||
|
||||
mixins: [
|
||||
Global
|
||||
],
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
form:{},
|
||||
email: email,
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onSubmit(event) {
|
||||
this.$emit('submit', event);
|
||||
event.submit();
|
||||
},
|
||||
|
||||
onCancel() {
|
||||
this.email.modal = false;
|
||||
this.email.html = null;
|
||||
|
||||
let documentClasses = document.body.classList;
|
||||
|
||||
documentClasses.remove('overflow-y-hidden', 'overflow-overlay', '-ml-4');
|
||||
},
|
||||
}
|
||||
})
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
})
|
||||
.finally(function () {
|
||||
// always executed
|
||||
});
|
||||
},
|
||||
|
||||
onEmailViaTemplate(route, template) {
|
||||
this.email_template = template;
|
||||
|
||||
this.onEmail(route);
|
||||
this.onSendEmail(route);
|
||||
},
|
||||
|
||||
// Change currency get money
|
||||
@ -1108,7 +803,7 @@ const app = new Vue({
|
||||
|
||||
let email_route = document.getElementById('senddocument_route').value;
|
||||
|
||||
this.onEmail(email_route);
|
||||
this.onSendEmail(email_route);
|
||||
}
|
||||
|
||||
this.page_loaded = true;
|
||||
|
@ -24,7 +24,7 @@ return [
|
||||
'create_recurring' => ':user created this recurring template on :date',
|
||||
'schedule' => 'Repeat every :interval :frequency since :date',
|
||||
'children' => ':count transactions were created automatically',
|
||||
'transfer_headline' => 'From :from_account to :to_account',
|
||||
'transfer_headline' => '<div> <span class="font-bold"> From: </span> :from_account </div> <div> <span class="font-bold"> to: </span> :to_account </div>',
|
||||
'transfer_desc' => 'Transfer created on :date.',
|
||||
],
|
||||
|
||||
|
@ -179,7 +179,7 @@
|
||||
@endsection
|
||||
|
||||
<x-slot name="content">
|
||||
<div class="dashboard flex flex-wrap -mx-12">
|
||||
<div class="dashboard flex flex-wrap lg:-mx-12">
|
||||
@foreach($widgets as $widget)
|
||||
@widget($widget)
|
||||
@endforeach
|
||||
|
@ -3,10 +3,10 @@
|
||||
<div class="overflow-y-hidden py-6">
|
||||
<table id="totals" class="float-right">
|
||||
<colgroup>
|
||||
<col style="width: 47.5%;">
|
||||
<col style="width: 30%;">
|
||||
<col style="width: 18%;">
|
||||
<col style="width: 50px;">
|
||||
<col class="small-col" style="width: 47.5%;">
|
||||
<col class="small-col" style="width: 30%;">
|
||||
<col class="small-col" style="width: 18%;">
|
||||
<col class="small-col" style="width: 50px;">
|
||||
</colgroup>
|
||||
|
||||
<tbody id="invoice-total-rows">
|
||||
|
@ -1,4 +1,4 @@
|
||||
<div id="{{ $id }}" role="tooltip" class="w-96 inline-block absolute left-0 z-10 text-sm font-medium rounded-lg border border-gray-200 shadow-sm whitespace-nowrap tooltip-content transition-visible bg-lilac-900 border-none text-black p-6 cursor-auto opacity-0 invisible information-content">
|
||||
<div id="{{ $id }}" role="tooltip" class="w-full lg:w-96 inline-block absolute left-0 z-10 text-sm font-medium rounded-lg border border-gray-200 shadow-sm whitespace-nowrap tooltip-content transition-visible bg-lilac-900 border-none text-black p-6 cursor-auto opacity-0 invisible information-content">
|
||||
<div class="absolute w-2 h-2 inset-y-1/2 -right-1 before:content-[' '] before:absolute before:w-2 before:h-2 before:bg-lilac-900 before:border-gray-200 before:transform before:rotate-45 before:border before:border-t-0 before:border-l-0 data-popper-arrow"></div>
|
||||
|
||||
<ul>
|
||||
|
@ -13,7 +13,7 @@
|
||||
@if (! $hideAddPayment)
|
||||
@if (empty($document->transactions->count()) || (! empty($document->transactions->count()) && $document->paid != $document->amount))
|
||||
<x-button
|
||||
@click="onPayment"
|
||||
@click="onAddPayment('{{ route('modals.documents.document.transactions.create', $document->id) }}')"
|
||||
id="show-slider-actions-payment-{{ $document->type }}"
|
||||
class="px-3 py-1.5 mb-3 sm:mb-0 rounded-lg text-xs font-medium leading-6 bg-green hover:bg-green-700 text-white disabled:bg-green-100"
|
||||
override="class"
|
||||
@ -80,7 +80,7 @@
|
||||
<span> - </span>
|
||||
|
||||
<x-button
|
||||
@click="onEditPayment('{{ $transaction->id }}')"
|
||||
@click="onEditPayment('{{ route('modals.documents.document.transactions.edit', ['document' => $document->id, 'transaction' => $transaction->id]) }}')"
|
||||
id="show-slider-actions-transaction-edit-{{ $document->type }}-{{ $transaction->id }}"
|
||||
class="text-purple mt-1"
|
||||
override="class"
|
||||
|
@ -13,7 +13,7 @@
|
||||
@if (! $hideAddPayment)
|
||||
@if(empty($document->transactions->count()) || (! empty($document->transactions->count()) && $document->paid != $document->amount))
|
||||
<x-button
|
||||
@click="onPayment"
|
||||
@click="onAddPayment('{{ route('modals.documents.document.transactions.create', $document->id) }}')"
|
||||
id="show-slider-actions-payment-{{ $document->type }}"
|
||||
class="px-3 py-1.5 mb-3 sm:mb-0 rounded-lg text-xs font-medium leading-6 bg-green hover:bg-green-700 text-white disabled:bg-green-100"
|
||||
override="class"
|
||||
@ -63,7 +63,7 @@
|
||||
<span> - </span>
|
||||
|
||||
<x-button
|
||||
@click="onEditPayment('{{ $transaction->id }}')"
|
||||
@click="onEditPayment('{{ route('modals.documents.document.transactions.edit', ['document' => $document->id, 'transaction' => $transaction->id]) }}')"
|
||||
id="show-slider-actions-transaction-edit-{{ $document->type }}-{{ $transaction->id }}"
|
||||
class="text-purple mt-1"
|
||||
override="class"
|
||||
|
@ -65,7 +65,7 @@
|
||||
|
||||
@if (! $hideEmail)
|
||||
@if ($document->contact_email)
|
||||
<x-dropdown.button id="show-more-actions-send-email-{{ $document->type }}" @click="onEmail('{{ route($emailRoute, $document->id) }}')">
|
||||
<x-dropdown.button id="show-more-actions-send-email-{{ $document->type }}" @click="onSendEmail('{{ route($emailRoute, $document->id) }}')">
|
||||
{{ trans($textEmail) }}
|
||||
</x-dropdown.button>
|
||||
@else
|
||||
|
@ -13,7 +13,7 @@
|
||||
<div class="flex flex-wrap space-x-3 rtl:space-x-reverse">
|
||||
@if (! $hideEmail)
|
||||
@if ($document->contact_email)
|
||||
<x-button id="show-slider-actions-send-email-{{ $document->type }}" kind="secondary" @click="onEmail('{{ route($emailRoute, $document->id) }}')">
|
||||
<x-button id="show-slider-actions-send-email-{{ $document->type }}" kind="secondary" @click="onSendEmail('{{ route($emailRoute, $document->id) }}')">
|
||||
{{ trans($textEmail) }}
|
||||
</x-button>
|
||||
@else
|
||||
|
@ -222,7 +222,7 @@
|
||||
<span class="material-icons text-lg text-purple transform ltr:rotate-90 rtl:-rotate-90 pointer-events-none">expand_circle_down</span>
|
||||
</button>
|
||||
|
||||
<span data-menu-close id="menu-cancel" class="material-icons absolute ltr:-right-2 rtl:right-12 transition-all top-8 text-lg text-purple cursor-pointer z-10 hidden pointer-events-none">cancel</span>
|
||||
<span data-menu-close id="menu-cancel" class="material-icons absolute ltr:-right-2 rtl:right-12 transition-all top-8 text-lg text-purple cursor-pointer z-10 hidden">cancel</span>
|
||||
|
||||
<div class="fixed w-full h-full invisible lg:hidden js-menu-background" style="background-color: rgba(0, 0, 0, 0.5); z-index: -1;"></div>
|
||||
</div>
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
@stack('body_start')
|
||||
|
||||
<div id="app" class="bg-no-repeat bg-cover bg-center" style="background-image: url({{ asset('public/img/auth/login-bg.png') }});">
|
||||
<div id="app" class="h-screen lg:h-auto bg-no-repeat bg-cover bg-center" style="background-image: url({{ asset('public/img/auth/login-bg.png') }});">
|
||||
<div class="relative w-full lg:max-w-7xl flex items-center m-auto">
|
||||
<x-layouts.auth.slider>
|
||||
{!! $slider ?? '' !!}
|
||||
|
@ -9,7 +9,7 @@
|
||||
<body>
|
||||
@stack('body_start')
|
||||
|
||||
<div class="bg-no-repeat bg-cover bg-center" style="background-image: url({{ asset('public/img/auth/login-bg.png') }});">
|
||||
<div class="h-screen lg:h-auto bg-no-repeat bg-cover bg-center" style="background-image: url({{ asset('public/img/auth/login-bg.png') }});">
|
||||
@if (! file_exists(public_path('js/install.min.js')))
|
||||
<div class="relative w-full lg:max-w-7xl flex flex-col lg:flex-row items-center m-auto">
|
||||
<div class="md:w-6/12 h-screen hidden lg:flex flex-col items-center justify-center">
|
||||
|
@ -169,7 +169,7 @@
|
||||
<span class="material-icons text-lg text-purple transform ltr:rotate-90 rtl:-rotate-90 pointer-events-none">expand_circle_down</span>
|
||||
</button>
|
||||
|
||||
<span data-menu-close class="material-icons absolute ltr:-right-2 rtl:right-12 transition-all top-8 text-lg text-purple cursor-pointer z-10 hidden pointer-events-none">cancel</span>
|
||||
<span data-menu-close class="material-icons absolute ltr:-right-2 rtl:right-12 transition-all top-8 text-lg text-purple cursor-pointer z-10 hidden">cancel</span>
|
||||
|
||||
<div class="fixed w-full h-full invisible lg:hidden js-menu-background" style="background-color: rgba(0, 0, 0, 0.5); z-index: -1;"></div>
|
||||
</div>
|
||||
|
@ -86,7 +86,7 @@
|
||||
@if ($transaction->isNotTransferTransaction())
|
||||
@if (! $hideButtonEmail)
|
||||
@if (! empty($transaction->contact) && $transaction->contact->email)
|
||||
<x-dropdown.button id="show-more-actions-send-email-{{ $transaction->type }}" @click="onEmail('{{ route($routeButtonEmail, $transaction->id) }}')">
|
||||
<x-dropdown.button id="show-more-actions-send-email-{{ $transaction->type }}" @click="onSendEmail('{{ route($routeButtonEmail, $transaction->id) }}')">
|
||||
{{ trans('invoices.send_mail') }}
|
||||
</x-dropdown.button>
|
||||
@else
|
||||
|
@ -16,7 +16,7 @@
|
||||
/>
|
||||
|
||||
@if ($transfer)
|
||||
<div class="text-black-400 text-sm flex gap-x-1 mt-1">
|
||||
<div class="text-black-400 text-sm space-y-3 mt-1">
|
||||
{!! trans('transactions.slider.transfer_headline', ['from_account' => $from_account, 'to_account' => $to_account]) !!}
|
||||
</div>
|
||||
@endif
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
<x-slot name="content">
|
||||
<div class="flex flex-col space-y-16 py-4">
|
||||
<div class="flex flex-col lg:flex-row w-full space-x-16 space-y-0">
|
||||
<div class="flex flex-col lg:flex-row w-full space-x-16 rtl:space-x-reverse space-y-0">
|
||||
<div class="w-full lg:w-7/12 flex flex-col space-x-2 banner">
|
||||
@foreach ($module->files as $file)
|
||||
@if ($loop->first)
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
<x-form.group.select name="type" label="{{ trans_choice('general.types', 1) }}" :options="$types" :selected="config('general.types')" change="updateParentCategories" />
|
||||
|
||||
<x-form.group.select name="parent_id" label="{{ trans('general.parent') . ' ' . trans_choice('general.categories', 1) }}" :options="[]" not-required dynamicOptions="categoriesBasedTypes" sort-options="false" v-disabled="isParentCategoryDisabled" />
|
||||
<x-form.group.select name="parent_id" label="{{ trans('general.parent') . ' ' . trans_choice('general.categories', 1) }}" :options="[]" not-required dynamicOptions="categoriesBasedTypes" sort-options="false" />
|
||||
|
||||
<x-form.input.hidden name="categories" value="{{ json_encode($categories) }}" />
|
||||
</x-slot>
|
||||
|
@ -1,7 +1,7 @@
|
||||
@if (! empty($module))
|
||||
{!! $module !!}
|
||||
@else
|
||||
<div class="relative w-full lg:w-1/2 my-8 px-12">
|
||||
<div class="relative w-full lg:w-1/2 my-8 lg:px-12">
|
||||
<div class="relative pb-2 my-4 lg:my-0 z-10">
|
||||
<div class="flex justify-between font-medium mb-2">
|
||||
<h2 class="text-black">
|
||||
@ -17,7 +17,7 @@
|
||||
</div>
|
||||
|
||||
<div class="relative flex justify-end -mt-28">
|
||||
<img src="https://assets.akaunting.com/software/admin/bank-feeds.png" alt="Bank Feeds" />
|
||||
<img src="https://assets.akaunting.com/software/admin/bank-feeds.png" class="rtl:-scale-x-100" alt="Bank Feeds" />
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
@ -6,11 +6,17 @@ lg:mt-4
|
||||
lg:pl-6
|
||||
lg:w-9
|
||||
lg:mt-11
|
||||
lg:-mx-12
|
||||
lg:w-96
|
||||
lg:px-3
|
||||
lg:px-4
|
||||
lg:px-6
|
||||
lg:relative
|
||||
lg:right-0
|
||||
lg:justify-around
|
||||
ltr:-right-1.5
|
||||
rtl:-left-1.5
|
||||
rtl:-scale-x-100
|
||||
sm:max-w-4xl
|
||||
hover:bg-silver-700
|
||||
hover:bg-peach_orange-700
|
||||
|
Loading…
x
Reference in New Issue
Block a user