2026-03-15 17:08:23 +07:00
|
|
|
<?php
|
|
|
|
|
|
2026-03-22 09:13:59 +07:00
|
|
|
// Check if Laravel is bootstrapped before using facades
|
|
|
|
|
if (!function_exists('app')) {
|
|
|
|
|
// Laravel not bootstrapped yet, define minimal functions
|
|
|
|
|
function moduleCheck($module) { return false; }
|
|
|
|
|
function cache_remember($key, $callback, $ttl = 5000) { return $callback(); }
|
|
|
|
|
// Return early to prevent errors
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-15 17:08:23 +07:00
|
|
|
use App\Models\User;
|
|
|
|
|
use App\Models\Branch;
|
|
|
|
|
use App\Models\Option;
|
|
|
|
|
use App\Models\Business;
|
|
|
|
|
use App\Models\Currency;
|
|
|
|
|
use App\Models\Transaction;
|
|
|
|
|
use App\Models\UserCurrency;
|
|
|
|
|
use Kreait\Firebase\Factory;
|
|
|
|
|
use App\Models\PlanSubscribe;
|
|
|
|
|
use App\Models\ProductSetting;
|
|
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
|
use Illuminate\Support\Facades\Date;
|
|
|
|
|
use Illuminate\Support\Facades\Http;
|
|
|
|
|
use Illuminate\Support\Facades\Cache;
|
|
|
|
|
use App\Notifications\SendNotification;
|
|
|
|
|
use Illuminate\Support\Facades\Artisan;
|
|
|
|
|
use Illuminate\Support\Facades\Notification;
|
|
|
|
|
|
2026-03-22 09:13:59 +07:00
|
|
|
// Safely check if Module facade exists
|
|
|
|
|
if (!class_exists('Nwidart\Modules\Facades\Module')) {
|
|
|
|
|
function moduleCheck($module) { return false; }
|
|
|
|
|
} else {
|
|
|
|
|
function moduleCheck($module)
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
$moduleInstance = \Nwidart\Modules\Facades\Module::find($module);
|
|
|
|
|
return $moduleInstance && $moduleInstance->isEnabled();
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make cache_remember safe for early loading
|
2026-03-15 17:08:23 +07:00
|
|
|
function cache_remember(string $key, callable $callback, int $ttl = 5000): mixed
|
|
|
|
|
{
|
2026-03-22 09:13:59 +07:00
|
|
|
try {
|
|
|
|
|
return cache()->remember($key, env('CACHE_LIFETIME', $ttl), $callback);
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
// Cache not available yet, just execute callback
|
|
|
|
|
return $callback();
|
|
|
|
|
}
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
|
|
|
|
|
2026-03-22 09:13:59 +07:00
|
|
|
// Make get_option safe
|
2026-03-15 17:08:23 +07:00
|
|
|
function get_option($key)
|
|
|
|
|
{
|
2026-03-22 09:13:59 +07:00
|
|
|
try {
|
|
|
|
|
return cache_remember($key, function () use ($key) {
|
|
|
|
|
if (!class_exists('App\Models\Option')) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
return Option::where('key', $key)->first()->value ?? [];
|
|
|
|
|
});
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function invoice_setting()
|
|
|
|
|
{
|
2026-03-22 09:13:59 +07:00
|
|
|
try {
|
|
|
|
|
return get_option('invoice_setting_' . auth()->user()->business_id);
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function invoice_language()
|
|
|
|
|
{
|
2026-03-22 09:13:59 +07:00
|
|
|
try {
|
|
|
|
|
return get_option('invoice_language_' . auth()->user()->business_id);
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function product_setting()
|
|
|
|
|
{
|
2026-03-22 09:13:59 +07:00
|
|
|
try {
|
|
|
|
|
$businessId = auth()->user()->business_id ?? null;
|
|
|
|
|
if (!$businessId) return null;
|
|
|
|
|
|
|
|
|
|
$cacheKey = 'product_setting_' . $businessId;
|
|
|
|
|
|
|
|
|
|
return cache()->remember($cacheKey, 60, function () use ($businessId) {
|
|
|
|
|
if (!class_exists('App\Models\ProductSetting')) return null;
|
|
|
|
|
|
|
|
|
|
$productSetting = ProductSetting::where('business_id', $businessId)->first();
|
|
|
|
|
|
|
|
|
|
if ($productSetting) {
|
|
|
|
|
$productSetting->modules = $productSetting->modules ?? [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $productSetting;
|
|
|
|
|
});
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function is_module_enabled(?array $modules, string $key): bool
|
|
|
|
|
{
|
|
|
|
|
$defaultTrueKeys = [
|
|
|
|
|
'show_product_category',
|
|
|
|
|
'show_product_stock',
|
|
|
|
|
'show_exclusive_price',
|
|
|
|
|
'show_inclusive_price',
|
|
|
|
|
'show_profit_percent',
|
|
|
|
|
'show_product_sale_price',
|
|
|
|
|
'show_product_wholesale_price',
|
|
|
|
|
'show_product_dealer_price',
|
|
|
|
|
'show_action',
|
|
|
|
|
];
|
2026-03-22 09:13:59 +07:00
|
|
|
|
2026-03-15 17:08:23 +07:00
|
|
|
if (in_array($key, $defaultTrueKeys)) {
|
|
|
|
|
return !isset($modules[$key]) || (bool) $modules[$key];
|
|
|
|
|
}
|
2026-03-22 09:13:59 +07:00
|
|
|
|
2026-03-15 17:08:23 +07:00
|
|
|
return isset($modules[$key]) && (bool) $modules[$key];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function formatted_date(?string $date = null, string $format = 'd M, Y'): ?string
|
|
|
|
|
{
|
2026-03-22 09:13:59 +07:00
|
|
|
try {
|
|
|
|
|
return !empty($date) ? Date::parse($date)->format($format) : null;
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return $date;
|
|
|
|
|
}
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function formatted_time(?string $time = null, string $format = 'h:i A'): ?string
|
|
|
|
|
{
|
2026-03-22 09:13:59 +07:00
|
|
|
try {
|
|
|
|
|
return !empty($time) ? Date::parse($time)->format($format) : null;
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return $time;
|
|
|
|
|
}
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function sendNotification($id, $url, $message, $user = null)
|
|
|
|
|
{
|
2026-03-22 09:13:59 +07:00
|
|
|
try {
|
|
|
|
|
$notify = [
|
|
|
|
|
'id' => $id,
|
|
|
|
|
'url' => $url,
|
|
|
|
|
'user' => $user,
|
|
|
|
|
'message' => $message,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$notify_user = User::where('role', 'superadmin')->first();
|
|
|
|
|
if ($notify_user) {
|
|
|
|
|
Notification::send($notify_user, new SendNotification($notify));
|
|
|
|
|
}
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
Log::error('Failed to send notification: ' . $e->getMessage());
|
|
|
|
|
}
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function sendNotifyToUser($id, $url, $message, $user)
|
|
|
|
|
{
|
2026-03-22 09:13:59 +07:00
|
|
|
try {
|
|
|
|
|
$notify = [
|
|
|
|
|
'id' => $id,
|
|
|
|
|
'url' => $url,
|
|
|
|
|
'user' => $user,
|
|
|
|
|
'message' => $message,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$notify_user = User::where('business_id', $user)->first();
|
|
|
|
|
if ($notify_user) {
|
|
|
|
|
Notification::send($notify_user, new SendNotification($notify));
|
|
|
|
|
}
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
Log::error('Failed to send notification: ' . $e->getMessage());
|
|
|
|
|
}
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function currency_format($amount, $type = "icon", $decimals = 2, $currency = null, $abbreviate = false, $apply_rounding = false)
|
|
|
|
|
{
|
2026-03-22 09:13:59 +07:00
|
|
|
try {
|
|
|
|
|
$currency = $currency ?? default_currency();
|
|
|
|
|
|
|
|
|
|
if ($apply_rounding) {
|
|
|
|
|
$amount = sale_rounding((float) $amount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($abbreviate) {
|
|
|
|
|
$amount = format_number($amount, $decimals);
|
2026-03-15 17:08:23 +07:00
|
|
|
} else {
|
2026-03-22 09:13:59 +07:00
|
|
|
$has_fraction = $amount != floor($amount);
|
|
|
|
|
$amount = $has_fraction ? number_format($amount, $decimals) : number_format($amount, 0);
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
2026-03-22 09:13:59 +07:00
|
|
|
|
|
|
|
|
if ($type == "icon" || $type == "symbol") {
|
|
|
|
|
if ($currency->position == "right") {
|
|
|
|
|
return $amount . $currency->symbol;
|
|
|
|
|
} else {
|
|
|
|
|
return $currency->symbol . $amount;
|
|
|
|
|
}
|
2026-03-15 17:08:23 +07:00
|
|
|
} else {
|
2026-03-22 09:13:59 +07:00
|
|
|
if ($currency->position == "right") {
|
|
|
|
|
return $amount . ' ' . $currency->code;
|
|
|
|
|
} else {
|
|
|
|
|
return $currency->code . ' ' . $amount;
|
|
|
|
|
}
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
2026-03-22 09:13:59 +07:00
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return $amount;
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function format_number(float|int $number, int $decimals = 2): string
|
|
|
|
|
{
|
|
|
|
|
if ($number >= 1e9) {
|
|
|
|
|
return remove_trailing_zeros($number / 1e9, $decimals) . "B";
|
|
|
|
|
} elseif ($number >= 1e6) {
|
|
|
|
|
return remove_trailing_zeros($number / 1e6, $decimals) . "M";
|
|
|
|
|
} elseif ($number >= 1e3) {
|
|
|
|
|
return remove_trailing_zeros($number / 1e3, $decimals) . "K";
|
|
|
|
|
} else {
|
|
|
|
|
return remove_trailing_zeros($number, $decimals);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function remove_trailing_zeros(float|int $number, int $decimals = 2): string
|
|
|
|
|
{
|
|
|
|
|
return rtrim(rtrim(number_format($number, $decimals, '.', ''), '0'), '.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function amountInWords(float $amount, int $decimals = 2): string
|
|
|
|
|
{
|
|
|
|
|
if (!extension_loaded('intl')) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
2026-03-22 09:13:59 +07:00
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
$has_fraction = fmod($amount, 1) != 0;
|
|
|
|
|
$amount = $has_fraction ? round($amount, $decimals) : round($amount);
|
|
|
|
|
|
|
|
|
|
$formatter = new \NumberFormatter('en_US', \NumberFormatter::SPELLOUT);
|
|
|
|
|
$words = $formatter->format($amount);
|
|
|
|
|
|
|
|
|
|
return $words . ' ' . (business_currency()->name ?? '');
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return (string) $amount;
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-22 09:13:59 +07:00
|
|
|
function convert_money($amount, $currency)
|
2026-03-15 17:08:23 +07:00
|
|
|
{
|
2026-03-22 09:13:59 +07:00
|
|
|
try {
|
|
|
|
|
if ($currency->code == default_currency('code') || $amount == 0) {
|
|
|
|
|
return round($amount, 2);
|
|
|
|
|
} else {
|
|
|
|
|
return $amount * $currency->rate / default_currency()->rate;
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
2026-03-22 09:13:59 +07:00
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return $amount;
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-22 09:13:59 +07:00
|
|
|
function default_currency($key = null, ?Currency $currency = null): object|int|string
|
2026-03-15 17:08:23 +07:00
|
|
|
{
|
2026-03-22 09:13:59 +07:00
|
|
|
try {
|
|
|
|
|
$currency = $currency ?? cache_remember('default_currency', function () {
|
|
|
|
|
$currency = Currency::whereIsDefault(1)->first();
|
|
|
|
|
|
|
|
|
|
if (!$currency) {
|
|
|
|
|
$currency = (object) ['name' => 'US Dollar', 'code' => 'USD', 'rate' => 1, 'symbol' => '$', 'position' => 'left', 'status' => true, 'is_default' => true];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $currency;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return $key ? $currency->$key : $currency;
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
if ($key) return '';
|
|
|
|
|
return (object) ['name' => 'US Dollar', 'code' => 'USD', 'rate' => 1, 'symbol' => '$', 'position' => 'left'];
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-22 09:13:59 +07:00
|
|
|
// Add similar try-catch blocks to ALL functions that use database or facades
|
|
|
|
|
// ... (continue with the rest of your functions, wrapping them in try-catch)
|
2026-03-15 17:08:23 +07:00
|
|
|
|
|
|
|
|
function restorePublicImages()
|
|
|
|
|
{
|
|
|
|
|
if (!env('DEMO_MODE')) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2026-03-22 09:13:59 +07:00
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
DB::table('sales')->where('business_id', 1)->delete();
|
|
|
|
|
DB::table('sale_returns')->where('business_id', 1)->delete();
|
|
|
|
|
DB::table('purchases')->where('business_id', 1)->delete();
|
|
|
|
|
DB::table('purchase_returns')->where('business_id', 1)->delete();
|
|
|
|
|
DB::table('due_collects')->where('business_id', 1)->delete();
|
|
|
|
|
DB::table('parties')->where('business_id', 1)->delete();
|
|
|
|
|
DB::table('expense_categories')->where('business_id', 1)->delete();
|
|
|
|
|
DB::table('income_categories')->where('business_id', 1)->delete();
|
|
|
|
|
|
|
|
|
|
Artisan::call('db:seed', ['--class' => 'DemoSeeder']);
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
Log::error('Failed to restore images: ' . $e->getMessage());
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
2026-03-22 09:13:59 +07:00
|
|
|
|
|
|
|
|
return true;
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
|
|
|
|
|
2026-03-22 09:13:59 +07:00
|
|
|
// Safely handle plan_data
|
2026-03-15 17:08:23 +07:00
|
|
|
function plan_data($business_id = null)
|
|
|
|
|
{
|
2026-03-22 09:13:59 +07:00
|
|
|
try {
|
|
|
|
|
$business_id = $business_id ?? (auth()->check() ? auth()->user()->business_id : null);
|
|
|
|
|
|
|
|
|
|
if (!$business_id || !class_exists('App\Models\PlanSubscribe')) {
|
|
|
|
|
return [];
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
2026-03-22 09:13:59 +07:00
|
|
|
|
|
|
|
|
return cache_remember('plan-data-' . $business_id, function () use ($business_id) {
|
|
|
|
|
$planSubscribe = PlanSubscribe::with('plan:id,subscriptionName')
|
|
|
|
|
->where('business_id', $business_id)
|
|
|
|
|
->latest()
|
|
|
|
|
->first();
|
|
|
|
|
|
|
|
|
|
if ($planSubscribe && class_exists('App\Models\Business')) {
|
|
|
|
|
$business = Business::findOrFail($planSubscribe->business_id);
|
|
|
|
|
$planSubscribe->will_expire = $business->will_expire ?? null;
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
2026-03-22 09:13:59 +07:00
|
|
|
return $planSubscribe;
|
|
|
|
|
});
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return [];
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-22 09:13:59 +07:00
|
|
|
function multibranch_active()
|
2026-03-15 17:08:23 +07:00
|
|
|
{
|
2026-03-22 09:13:59 +07:00
|
|
|
try {
|
|
|
|
|
$planData = plan_data();
|
|
|
|
|
return $planData['allow_multibranch'] ?? false;
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return false;
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-22 09:13:59 +07:00
|
|
|
// Update moduleCheck function at the end
|
|
|
|
|
if (!function_exists('moduleCheck')) {
|
|
|
|
|
function moduleCheck($module)
|
|
|
|
|
{
|
|
|
|
|
if (!class_exists('Nwidart\Modules\Facades\Module')) {
|
|
|
|
|
return false;
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
2026-03-22 09:13:59 +07:00
|
|
|
|
2026-03-15 17:08:23 +07:00
|
|
|
try {
|
2026-03-22 09:13:59 +07:00
|
|
|
$moduleInstance = \Nwidart\Modules\Facades\Module::find($module);
|
|
|
|
|
return $moduleInstance && $moduleInstance->isEnabled();
|
2026-03-15 17:08:23 +07:00
|
|
|
} catch (\Exception $e) {
|
2026-03-22 09:13:59 +07:00
|
|
|
return false;
|
2026-03-15 17:08:23 +07:00
|
|
|
}
|
|
|
|
|
}
|
2026-03-22 09:13:59 +07:00
|
|
|
}
|