migrate to gtea from bistbucket
This commit is contained in:
27
app/Console/Kernel.php
Normal file
27
app/Console/Kernel.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console;
|
||||
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
|
||||
class Kernel extends ConsoleKernel
|
||||
{
|
||||
/**
|
||||
* Define the application's command schedule.
|
||||
*/
|
||||
protected function schedule(Schedule $schedule): void
|
||||
{
|
||||
$schedule->command('demo:restore-public-images')->everyThirtyMinutes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the commands for the application.
|
||||
*/
|
||||
protected function commands(): void
|
||||
{
|
||||
$this->load(__DIR__.'/Commands');
|
||||
|
||||
require base_path('routes/console.php');
|
||||
}
|
||||
}
|
||||
39
app/Events/DuePaymentReceived.php
Normal file
39
app/Events/DuePaymentReceived.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\DueCollect;
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PresenceChannel;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class DuePaymentReceived
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public $due_collect;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*/
|
||||
public function __construct(DueCollect $due_collect)
|
||||
{
|
||||
$this->due_collect = $due_collect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*
|
||||
* @return array<int, \Illuminate\Broadcasting\Channel>
|
||||
*/
|
||||
public function broadcastOn(): array
|
||||
{
|
||||
return [
|
||||
new PrivateChannel('channel-name'),
|
||||
];
|
||||
}
|
||||
}
|
||||
44
app/Events/MultiPaymentProcessed.php
Normal file
44
app/Events/MultiPaymentProcessed.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class MultiPaymentProcessed
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public $payments;
|
||||
public $business_id;
|
||||
public $reference_id;
|
||||
public $platform;
|
||||
public $receiveAmount;
|
||||
public $party_id;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*/
|
||||
public function __construct($payments, $reference_id, $platform, $receiveAmount = 0, $party_id = null)
|
||||
{
|
||||
$this->payments = $payments;
|
||||
$this->reference_id = $reference_id;
|
||||
$this->platform = $platform;
|
||||
$this->receiveAmount = $receiveAmount;
|
||||
$this->party_id = $party_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*
|
||||
* @return array<int, \Illuminate\Broadcasting\Channel>
|
||||
*/
|
||||
public function broadcastOn(): array
|
||||
{
|
||||
return [
|
||||
new PrivateChannel('channel-name'),
|
||||
];
|
||||
}
|
||||
}
|
||||
39
app/Events/PurchaseSms.php
Normal file
39
app/Events/PurchaseSms.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\Purchase;
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PresenceChannel;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class PurchaseSms
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public $purchase;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*/
|
||||
public function __construct(Purchase $purchase)
|
||||
{
|
||||
$this->purchase = $purchase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*
|
||||
* @return array<int, \Illuminate\Broadcasting\Channel>
|
||||
*/
|
||||
public function broadcastOn(): array
|
||||
{
|
||||
return [
|
||||
new PrivateChannel('channel-name'),
|
||||
];
|
||||
}
|
||||
}
|
||||
39
app/Events/SaleSms.php
Normal file
39
app/Events/SaleSms.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\Sale;
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Broadcasting\PresenceChannel;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
|
||||
class SaleSms
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public $sale;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*/
|
||||
public function __construct(Sale $sale)
|
||||
{
|
||||
$this->sale = $sale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*
|
||||
* @return array<int, \Illuminate\Broadcasting\Channel>
|
||||
*/
|
||||
public function broadcastOn(): array
|
||||
{
|
||||
return [
|
||||
new PrivateChannel('channel-name'),
|
||||
];
|
||||
}
|
||||
}
|
||||
30
app/Exceptions/Handler.php
Normal file
30
app/Exceptions/Handler.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
use Throwable;
|
||||
|
||||
class Handler extends ExceptionHandler
|
||||
{
|
||||
/**
|
||||
* The list of the inputs that are never flashed to the session on validation exceptions.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $dontFlash = [
|
||||
'current_password',
|
||||
'password',
|
||||
'password_confirmation',
|
||||
];
|
||||
|
||||
/**
|
||||
* Register the exception handling callbacks for the application.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
$this->reportable(function (Throwable $e) {
|
||||
//
|
||||
});
|
||||
}
|
||||
}
|
||||
70
app/Helpers/HasUploader.php
Normal file
70
app/Helpers/HasUploader.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
trait HasUploader
|
||||
{
|
||||
private function upload(Request $request, $input, $oldFile = null, $disk = null)
|
||||
{
|
||||
$file = $request->file($input);
|
||||
$ext = $file->getClientOriginalExtension();
|
||||
$filename = now()->timestamp . '-' . rand(1, 1000) . '.' . $ext;
|
||||
|
||||
$path = 'uploads/' . date('y') . '/' . date('m') . '/';
|
||||
$filePath = $path . $filename;
|
||||
|
||||
if ($oldFile) {
|
||||
if (file_exists($oldFile)) {
|
||||
Storage::delete($oldFile);
|
||||
}
|
||||
}
|
||||
|
||||
Storage::disk($disk ?? config('filesystems.default'))->put($filePath, file_get_contents($file));
|
||||
return $filePath;
|
||||
}
|
||||
|
||||
private function uploadWithFileName(Request $request, $input, $oldFile = null, $disk = null)
|
||||
{
|
||||
$file = $request->file($input);
|
||||
$filename = $file->getClientOriginalName();
|
||||
|
||||
$path = 'files/';
|
||||
$filePath = $path . $filename;
|
||||
|
||||
if ($oldFile) {
|
||||
if (file_exists($oldFile)) {
|
||||
Storage::delete($oldFile);
|
||||
}
|
||||
}
|
||||
|
||||
Storage::disk($disk ?? config('filesystems.default'))->put($filePath, file_get_contents($file));
|
||||
return $filePath;
|
||||
}
|
||||
|
||||
private function multipleUpload(Request $request, $input, $oldFiles = [], $disk = null)
|
||||
{
|
||||
$uploadedFiles = [];
|
||||
|
||||
foreach ($request->file($input) as $file) {
|
||||
$ext = $file->getClientOriginalExtension();
|
||||
$filename = now()->timestamp . '_' . uniqid() . '.' . $ext;
|
||||
|
||||
$path = 'uploads/' . date('y') . '/' . date('m') . '/';
|
||||
$filePath = $path . $filename;
|
||||
|
||||
foreach ($oldFiles as $oldFile) {
|
||||
if (file_exists($oldFile)) {
|
||||
Storage::delete($oldFile);
|
||||
}
|
||||
}
|
||||
|
||||
Storage::disk($disk ?? config('filesystems.default'))->put($filePath, file_get_contents($file));
|
||||
$uploadedFiles[] = $filePath;
|
||||
}
|
||||
|
||||
return $uploadedFiles;
|
||||
}
|
||||
}
|
||||
793
app/Helpers/Helper.php
Normal file
793
app/Helpers/Helper.php
Normal file
@@ -0,0 +1,793 @@
|
||||
<?php
|
||||
|
||||
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 Nwidart\Modules\Facades\Module;
|
||||
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 Modules\MarketingAddon\App\Models\Sim;
|
||||
use Kreait\Firebase\Messaging\CloudMessage;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Modules\MarketingAddon\App\Models\Device;
|
||||
use Modules\MarketingAddon\App\Models\Smsgateway;
|
||||
|
||||
function cache_remember(string $key, callable $callback, int $ttl = 5000): mixed
|
||||
{
|
||||
return cache()->remember($key, env('CACHE_LIFETIME', $ttl), $callback);
|
||||
}
|
||||
|
||||
function get_option($key)
|
||||
{
|
||||
return cache_remember($key, function () use ($key) {
|
||||
return Option::where('key', $key)->first()->value ?? [];
|
||||
});
|
||||
}
|
||||
|
||||
function invoice_setting()
|
||||
{
|
||||
return get_option('invoice_setting_' . auth()->user()->business_id);
|
||||
}
|
||||
|
||||
function invoice_language()
|
||||
{
|
||||
return get_option('invoice_language_' . auth()->user()->business_id);
|
||||
}
|
||||
|
||||
function product_setting()
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$cacheKey = 'product_setting_' . $businessId;
|
||||
|
||||
return cache()->remember($cacheKey, 60, function () use ($businessId) {
|
||||
$productSetting = ProductSetting::where('business_id', $businessId)->first();
|
||||
|
||||
if ($productSetting) {
|
||||
$productSetting->modules = $productSetting->modules ?? [];
|
||||
}
|
||||
|
||||
return $productSetting;
|
||||
});
|
||||
}
|
||||
|
||||
function is_module_enabled(?array $modules, string $key): bool
|
||||
{
|
||||
// Keys that should default to true if not set
|
||||
$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',
|
||||
];
|
||||
|
||||
if (in_array($key, $defaultTrueKeys)) {
|
||||
return !isset($modules[$key]) || (bool) $modules[$key];
|
||||
}
|
||||
|
||||
// All other keys: show only if explicitly set to true
|
||||
return isset($modules[$key]) && (bool) $modules[$key];
|
||||
}
|
||||
|
||||
function formatted_date(?string $date = null, string $format = 'd M, Y'): ?string
|
||||
{
|
||||
return !empty($date) ? Date::parse($date)->format($format) : null;
|
||||
}
|
||||
|
||||
function formatted_time(?string $time = null, string $format = 'h:i A'): ?string
|
||||
{
|
||||
return !empty($time) ? Date::parse($time)->format($format) : null;
|
||||
}
|
||||
|
||||
function sendNotification($id, $url, $message, $user = null)
|
||||
{
|
||||
$notify = [
|
||||
'id' => $id,
|
||||
'url' => $url,
|
||||
'user' => $user,
|
||||
'message' => $message,
|
||||
];
|
||||
|
||||
$notify_user = User::where('role', 'superadmin')->first();
|
||||
Notification::send($notify_user, new SendNotification($notify));
|
||||
}
|
||||
|
||||
function sendNotifyToUser($id, $url, $message, $user)
|
||||
{
|
||||
$notify = [
|
||||
'id' => $id,
|
||||
'url' => $url,
|
||||
'user' => $user,
|
||||
'message' => $message,
|
||||
];
|
||||
|
||||
$notify_user = User::where('business_id', $user)->first();
|
||||
Notification::send($notify_user, new SendNotification($notify));
|
||||
}
|
||||
|
||||
function currency_format($amount, $type = "icon", $decimals = 2, $currency = null, $abbreviate = false, $apply_rounding = false)
|
||||
{
|
||||
$currency = $currency ?? default_currency();
|
||||
|
||||
if ($apply_rounding) {
|
||||
$amount = sale_rounding((float) $amount);
|
||||
}
|
||||
|
||||
if ($abbreviate) {
|
||||
$amount = format_number($amount, $decimals);
|
||||
} else {
|
||||
$has_fraction = $amount != floor($amount);
|
||||
$amount = $has_fraction ? number_format($amount, $decimals) : number_format($amount, 0);
|
||||
}
|
||||
|
||||
if ($type == "icon" || $type == "symbol") {
|
||||
if ($currency->position == "right") {
|
||||
return $amount . $currency->symbol;
|
||||
} else {
|
||||
return $currency->symbol . $amount;
|
||||
}
|
||||
} else {
|
||||
if ($currency->position == "right") {
|
||||
return $amount . ' ' . $currency->code;
|
||||
} else {
|
||||
return $currency->code . ' ' . $amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 '';
|
||||
}
|
||||
|
||||
$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 ?? '');
|
||||
}
|
||||
|
||||
function convert_money($amount, $currency)
|
||||
{
|
||||
if ($currency->code == default_currency('code') || $amount == 0) {
|
||||
return round($amount, 2);
|
||||
} else {
|
||||
return $amount * $currency->rate / default_currency()->rate;
|
||||
}
|
||||
}
|
||||
|
||||
function default_currency($key = null, ?Currency $currency = null): object|int|string
|
||||
{
|
||||
$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;
|
||||
}
|
||||
|
||||
function paymentReminderMessage($sale, $business, $customer_name = 'Customer')
|
||||
{
|
||||
$message = get_option('sms-templates-' . $business->id)['purchase_sms'] ?? "Hello [customer_name], kindly clear your outstanding balance of [amount]. For details, contact us at [business_phone].";
|
||||
|
||||
$data = [
|
||||
'customer_name' => $customer_name,
|
||||
'invoice_no' => $sale->invoiceNumber,
|
||||
'due_amount' => $sale->totalAmount,
|
||||
'date' => formatted_date($sale->saleDate),
|
||||
'business_name' => $business->companyName,
|
||||
'business_phone' => $business->phoneNumber,
|
||||
];
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
$message = str_replace("[$key]", $value, $message);
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
function sendMessage($numbers, $contents, $business_id = null)
|
||||
{
|
||||
$gateways = Smsgateway::where('business_id', $business_id ?? auth()->user()->business_id)->where('status', 1)->get();
|
||||
|
||||
foreach ($gateways as $gateway) {
|
||||
$gateway->namespace::send_message($gateway, $numbers, $contents);
|
||||
session()->put('gateway_id', $gateway->id);
|
||||
|
||||
return [
|
||||
'status' => true,
|
||||
'message' => "Message send successfully."
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
function sendPushNotify($request, int|string $total_numbers, ?int $device_id = null): bool
|
||||
{
|
||||
$credentialPath = public_path('uploads/service-account-credentials.json');
|
||||
if (!file_exists($credentialPath))
|
||||
return false;
|
||||
|
||||
$firebase = (new Factory)->withServiceAccount($credentialPath)->createMessaging();
|
||||
$tokens = [];
|
||||
|
||||
if ($device_id) {
|
||||
$tokens = Device::whereNotNull('device_token')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->where('id', $device_id)
|
||||
->pluck('device_token');
|
||||
} else {
|
||||
$device_ids = Sim::whereIn('id', $request->sim_ids)->pluck('device_id')->unique();
|
||||
$tokens = Device::whereNotNull('device_token')->whereIn('id', $device_ids)->pluck('device_token');
|
||||
}
|
||||
|
||||
foreach ($tokens as $token) {
|
||||
$message = CloudMessage::fromArray([
|
||||
'notification' => [
|
||||
'title' => 'New ' . $request->type . ' has been created.',
|
||||
'body' => $total_numbers . ' ' . $request->type . ' has been created.',
|
||||
],
|
||||
'data' => ['type' => $request->type],
|
||||
'token' => $token,
|
||||
]);
|
||||
|
||||
try {
|
||||
$firebase->send($message);
|
||||
} catch (\Kreait\Firebase\Exception\MessagingException $e) {
|
||||
Log::error('Firebase Notification Error', ['error' => $e->getMessage()]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function restorePublicImages()
|
||||
{
|
||||
if (!env('DEMO_MODE')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
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']);
|
||||
}
|
||||
|
||||
if (!function_exists('formatTimeToWords')) {
|
||||
function formatTimeToWords(string|null $time): string
|
||||
{
|
||||
if (empty($time)) {
|
||||
return '0';
|
||||
}
|
||||
|
||||
if (!preg_match('/^\d{1,2}:\d{2}(:\d{2})?$/', $time)) {
|
||||
return '0';
|
||||
}
|
||||
|
||||
$parts = explode(':', $time);
|
||||
|
||||
$hours = isset($parts[0]) ? (int) $parts[0] : 0;
|
||||
$minutes = isset($parts[1]) ? (int) $parts[1] : 0;
|
||||
|
||||
$hourString = $hours == 1 ? 'hour' : 'hours';
|
||||
$minuteString = $minutes == 1 ? 'minute' : 'minutes';
|
||||
|
||||
$formattedTime = [];
|
||||
|
||||
if ($hours > 0) {
|
||||
$formattedTime[] = "$hours $hourString";
|
||||
}
|
||||
|
||||
if ($minutes > 0) {
|
||||
$formattedTime[] = "$minutes $minuteString";
|
||||
}
|
||||
|
||||
return empty($formattedTime) ? '0' : implode(' and ', $formattedTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function languages()
|
||||
{
|
||||
return [
|
||||
'en' => ['name' => 'English', 'flag' => 'us'],
|
||||
'ar' => ['name' => 'Arabic', 'flag' => 'sa'],
|
||||
'bn' => ['name' => 'Bengali', 'flag' => 'bd'],
|
||||
'zh' => ['name' => 'Chinese', 'flag' => 'cn'],
|
||||
'fr' => ['name' => 'French', 'flag' => 'fr'],
|
||||
'de' => ['name' => 'German', 'flag' => 'de'],
|
||||
'hi' => ['name' => 'Hindi', 'flag' => 'in'],
|
||||
'es' => ['name' => 'Spanish', 'flag' => 'es'],
|
||||
'ja' => ['name' => 'Japanese', 'flag' => 'jp'],
|
||||
'rum' => ['name' => 'Romanian', 'flag' => 'ro'],
|
||||
'vi' => ['name' => 'Vietnamese', 'flag' => 'vn'],
|
||||
'it' => ['name' => 'Italian', 'flag' => 'it'],
|
||||
'th' => ['name' => 'Thai', 'flag' => 'th'],
|
||||
'bs' => ['name' => 'Bosnian', 'flag' => 'ba'],
|
||||
'nl' => ['name' => 'Dutch', 'flag' => 'nl'],
|
||||
'pt' => ['name' => 'Portuguese', 'flag' => 'pt'],
|
||||
'pl' => ['name' => 'Polish', 'flag' => 'pl'],
|
||||
'he' => ['name' => 'Hebrew', 'flag' => 'il'],
|
||||
'hu' => ['name' => 'Hungarian', 'flag' => 'hu'],
|
||||
'fi' => ['name' => 'Finnish', 'flag' => 'fi'],
|
||||
'el' => ['name' => 'Greek', 'flag' => 'gr'],
|
||||
'ko' => ['name' => 'Korean', 'flag' => 'kr'],
|
||||
'ms' => ['name' => 'Malay', 'flag' => 'my'],
|
||||
'id' => ['name' => 'Indonesian', 'flag' => 'id'],
|
||||
'fa' => ['name' => 'Persian', 'flag' => 'ir'],
|
||||
'tr' => ['name' => 'Turkish', 'flag' => 'tr'],
|
||||
'sr' => ['name' => 'Serbian', 'flag' => 'rs'],
|
||||
'km' => ['name' => 'Khmer', 'flag' => 'khm'],
|
||||
'uk' => ['name' => 'Ukrainian', 'flag' => 'ua'],
|
||||
'lo' => ['name' => 'Lao', 'flag' => 'la'],
|
||||
'ru' => ['name' => 'Russian', 'flag' => 'ru'],
|
||||
'cs' => ['name' => 'Czech', 'flag' => 'cz'],
|
||||
'kn' => ['name' => 'Kannada', 'flag' => 'ka'],
|
||||
'mr' => ['name' => 'Marathi', 'flag' => 'mh'],
|
||||
'sv' => ['name' => 'Swedish', 'flag' => 'se'],
|
||||
'da' => ['name' => 'Danish', 'flag' => 'dk'],
|
||||
'ur' => ['name' => 'Urdu', 'flag' => 'pk'],
|
||||
'sq' => ['name' => 'Albanian', 'flag' => 'al'],
|
||||
'sk' => ['name' => 'Slovak', 'flag' => 'sk'],
|
||||
'bur' => ['name' => 'Burmese', 'flag' => 'mm'],
|
||||
'ti' => ['name' => 'Tigrinya', 'flag' => 'er'],
|
||||
'kz' => ['name' => 'Kazakh', 'flag' => 'kz'],
|
||||
'az' => ['name' => 'Azerbaijani', 'flag' => 'az'],
|
||||
'zh-cn' => ['name' => 'Chinese (CN)', 'flag' => 'zh-cn'],
|
||||
'zh-tw' => ['name' => 'Chinese (TW)', 'flag' => 'zh-tw'],
|
||||
'pt-br' => ['name' => 'Portuguese (BR)', 'flag' => 'pt-br'],
|
||||
'tz' => ['name' => 'Swahili', 'flag' => 'tz'],
|
||||
'ps' => ['name' => 'Pashto', 'flag' => 'af'],
|
||||
'prs' => ['name' => 'Dari', 'flag' => 'afdari'],
|
||||
'ca' => ['name' => 'Catalan', 'flag' => 'ad'],
|
||||
'bt' => ['name' => 'Dzongkha', 'flag' => 'dz'],
|
||||
'drcfr' => ['name' => 'Congo (DRC)', 'flag' => 'drc'],
|
||||
'cgfr' => ['name' => 'Congo (Republic)', 'flag' => 'cg'],
|
||||
'escr' => ['name' => 'Costa Rica (Spanish)', 'flag' => 'cr'],
|
||||
'enbw' => ['name' => 'Botswana (English)', 'flag' => 'bw'],
|
||||
'bws' => ['name' => 'Botswana (Setswana)', 'flag' => 'bws'],
|
||||
'deat' => ['name' => 'Austria(German)', 'flag' => 'at'],
|
||||
'enbs' => ['name' => 'Bahamas(English)', 'flag' => 'bs'],
|
||||
'arbh' => ['name' => 'Bahrain(Arabic)', 'flag' => 'bh'],
|
||||
'pt-ao' => ['name' => 'Angola(Portuguese)', 'flag' => 'ao'],
|
||||
'es-ar' => ['name' => 'Argentina(Spanish)', 'flag' => 'ar'],
|
||||
'hy' => ['name' => 'Armenian', 'flag' => 'am'],
|
||||
'au-en' => ['name' => 'Australia', 'flag' => 'au'],
|
||||
'bb-en' => ['name' => 'Barbados(English)', 'flag' => 'bb'],
|
||||
'be' => ['name' => 'Belarusian', 'flag' => 'by'],
|
||||
'nl-be' => ['name' => 'Belgium(Dutch)', 'flag' => 'be'],
|
||||
'bz-en' => ['name' => 'Belize(English)', 'flag' => 'bz'],
|
||||
'bj-fr' => ['name' => 'Benin(French)', 'flag' => 'bj'],
|
||||
'bo-es' => ['name' => 'Bolivia(Spanish)', 'flag' => 'bo'],
|
||||
'bn-ms' => ['name' => 'Brunei(Malay)', 'flag' => 'bn'],
|
||||
'bg' => ['name' => 'Bulgarian', 'flag' => 'bg'],
|
||||
'bf-fr' => ['name' => 'Burkina Faso(French)', 'flag' => 'bf'],
|
||||
'cm-fr' => ['name' => 'Cameroon(French)', 'flag' => 'cm'],
|
||||
'ca-en' => ['name' => 'Canada(English)', 'flag' => 'ca'],
|
||||
'cl-es' => ['name' => 'Chile(Spanish)', 'flag' => 'cl'],
|
||||
'co-es' => ['name' => 'Colombia(Spanish)', 'flag' => 'co'],
|
||||
'km-ar' => ['name' => 'Comoros(Arabic)', 'flag' => 'km'],
|
||||
'hr' => ['name' => 'Croatian', 'flag' => 'hr'],
|
||||
'cu-es' => ['name' => 'Cuba(Spanish)', 'flag' => 'cu'],
|
||||
'cy-el' => ['name' => 'Cyprus(Greek)', 'flag' => 'cy'],
|
||||
'dj-fr' => ['name' => 'Djibouti(French)', 'flag' => 'dj'],
|
||||
'dm-en' => ['name' => 'Dominica(English)', 'flag' => 'dm'],
|
||||
'tet' => ['name' => 'Tetum', 'flag' => 'tl'],
|
||||
'ec-es' => ['name' => 'Ecuador(Spanish)', 'flag' => 'ec'],
|
||||
'eg-ar' => ['name' => 'Egypt(Arabic)', 'flag' => 'eg'],
|
||||
'sv-es' => ['name' => 'El Salvador(Spanish)', 'flag' => 'sv'],
|
||||
'gq-es' => ['name' => 'Equatorial Guinea(Spanish)', 'flag' => 'gq'],
|
||||
'et' => ['name' => 'Estonian', 'flag' => 'ee'],
|
||||
'ss' => ['name' => 'Swati', 'flag' => 'sz'],
|
||||
'am' => ['name' => 'Amharic', 'flag' => 'et'],
|
||||
'fj' => ['name' => 'Fijian', 'flag' => 'fj'],
|
||||
'ga-fr' => ['name' => 'Gabon(French)', 'flag' => 'ga'],
|
||||
'gm-en' => ['name' => 'Gambia(English)', 'flag' => 'gm'],
|
||||
'ka' => ['name' => 'Georgian', 'flag' => 'ge'],
|
||||
'gh-en' => ['name' => 'Ghana(English)', 'flag' => 'gh'],
|
||||
'gd-en' => ['name' => 'Grenada(English)', 'flag' => 'gd'],
|
||||
'gt-en' => ['name' => 'Guatemala(English)', 'flag' => 'gt'],
|
||||
'gn-fr' => ['name' => 'Guinea(French)', 'flag' => 'gn'],
|
||||
'gy-en' => ['name' => 'Guyana(English)', 'flag' => 'gy'],
|
||||
'ht-fr' => ['name' => 'Haiti(French)', 'flag' => 'ht'],
|
||||
'hn-es' => ['name' => 'Honduras(Spanish)', 'flag' => 'hn'],
|
||||
];
|
||||
}
|
||||
|
||||
// BUSINESS PANEL
|
||||
|
||||
// user role permission
|
||||
if (!function_exists('visible_permission')) {
|
||||
function visible_permission($permission)
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
// Ensure the user is authenticated and has a business_id
|
||||
if (!$user || !$user->business_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle visibility field directly as an array or decode it if it's a string
|
||||
$permissions = is_array($user->visibility)
|
||||
? $user->visibility
|
||||
: json_decode($user->visibility, true);
|
||||
|
||||
return $permissions[$permission] ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_business_option($key)
|
||||
{
|
||||
$cacheKey = "business_setting_" . auth()->user()->business_id;
|
||||
|
||||
return Cache::remember($cacheKey, now()->addDay(), function () use ($key) {
|
||||
if ($key == 'business-settings') {
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$option = Option::where('key', 'business-settings')
|
||||
->where('value', 'LIKE', '%"business_id":%' . $business_id . '%')
|
||||
->get()
|
||||
->firstWhere('value.business_id', $business_id);
|
||||
|
||||
return $option ? $option->value : null;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
function plan_data($business_id = null)
|
||||
{
|
||||
$business_id = $business_id ?? auth()->user()->business_id;
|
||||
|
||||
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) {
|
||||
$business = Business::findOrFail($planSubscribe->business_id);
|
||||
$planSubscribe->will_expire = $business->will_expire;
|
||||
}
|
||||
return $planSubscribe;
|
||||
});
|
||||
}
|
||||
|
||||
function branch_count()
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
return cache_remember('branch-count-' . $business_id, function () use ($business_id) {
|
||||
$totalBranch = Branch::where('business_id', $business_id)->count();
|
||||
|
||||
return $totalBranch;
|
||||
});
|
||||
}
|
||||
|
||||
function multibranch_active()
|
||||
{
|
||||
return plan_data()['allow_multibranch'] ?? false;
|
||||
}
|
||||
|
||||
function business_currency($business_id = null)
|
||||
{
|
||||
$business_id = $business_id ?? auth()->user()->business_id;
|
||||
|
||||
return cache_remember("business_currency_{$business_id}", function () use ($business_id) {
|
||||
$businessCurrency = UserCurrency::where('business_id', $business_id)->first() ?? Currency::where('is_default', 1)->first();
|
||||
;
|
||||
|
||||
if ($businessCurrency) {
|
||||
return (object) [
|
||||
'name' => $businessCurrency->name,
|
||||
'rate' => $businessCurrency->rate,
|
||||
'code' => $businessCurrency->code,
|
||||
'symbol' => $businessCurrency->symbol,
|
||||
'position' => $businessCurrency->position,
|
||||
];
|
||||
}
|
||||
|
||||
return default_currency();
|
||||
});
|
||||
}
|
||||
|
||||
function sale_rounding(?float $amount = null, ?string $round_option = null): float|string
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
// If $round_option is not passed, try to fetch from settings
|
||||
if (is_null($round_option)) {
|
||||
$round_option = cache_remember("business_sale_rounding_{$business_id}", function () use ($business_id) {
|
||||
$option = Option::where('key', 'business-settings')
|
||||
->where('value', 'LIKE', '%"business_id":%' . $business_id . '%')
|
||||
->get()
|
||||
->firstWhere('value.business_id', $business_id);
|
||||
|
||||
return $option ? ($option->value['sale_rounding_option'] ?? 'none') : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
if (is_null($amount)) {
|
||||
return $round_option;
|
||||
}
|
||||
|
||||
// Apply rounding if amount is provided
|
||||
return match ($round_option) {
|
||||
'round_up' => ceil($amount),
|
||||
'nearest_whole_number' => round($amount),
|
||||
'nearest_0.05' => round($amount * 20) / 20,
|
||||
'nearest_0.1' => round($amount * 10) / 10,
|
||||
'nearest_0.5' => round($amount * 2) / 2,
|
||||
default => $amount,
|
||||
};
|
||||
}
|
||||
|
||||
function moduleCheck($module)
|
||||
{
|
||||
$module = Module::find($module);
|
||||
|
||||
if ($module && $module->isEnabled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function remaining_days($date)
|
||||
{
|
||||
$today = \Carbon\Carbon::today();
|
||||
$expiry = \Carbon\Carbon::parse($date);
|
||||
$diff = $today->diffInDays($expiry, false);
|
||||
|
||||
return $diff > 0 ? "$diff days" : "";
|
||||
}
|
||||
|
||||
// update RemainingBalance
|
||||
function updateBalance($amount, string $type, $branch_id = null)
|
||||
{
|
||||
$amount = is_numeric($amount) ? (float) $amount : 0;
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
// if active branch, then update active branch
|
||||
$branch = auth()->user()->active_branch;
|
||||
if ($branch) {
|
||||
if ($type == 'increment') {
|
||||
$branch->increment('branchRemainingBalance', $amount);
|
||||
} elseif ($type == 'decrement') {
|
||||
$branch->decrement('branchRemainingBalance', $amount);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//If branch_id is provided, update that branch
|
||||
if ($branch_id) {
|
||||
$branch = Branch::find($branch_id);
|
||||
if ($branch) {
|
||||
if ($type == 'increment') {
|
||||
$branch->increment('branchRemainingBalance', $amount);
|
||||
} elseif ($type == 'decrement') {
|
||||
$branch->decrement('branchRemainingBalance', $amount);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If no branch, update business balance
|
||||
$business = Business::find($businessId);
|
||||
if ($business) {
|
||||
if ($type == 'increment') {
|
||||
$business->increment('remainingShopBalance', $amount);
|
||||
} elseif ($type == 'decrement') {
|
||||
$business->decrement('remainingShopBalance', $amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function manipulateBranchData($business_id)
|
||||
{
|
||||
$business = auth()->user()->business;
|
||||
$shop_owner = User::where(['business_id' => $business_id, 'role' => 'shop-owner'])->firstOrFail();
|
||||
|
||||
$branch = Branch::create([
|
||||
'is_main' => 1,
|
||||
'email' => $shop_owner->email,
|
||||
'name' => $business->companyName,
|
||||
'phone' => $business->phoneNumber,
|
||||
'address' => $business->address
|
||||
]);
|
||||
|
||||
$updates = [
|
||||
'users' => ['branch_id' => $branch->id, 'where' => ['role' => 'staff']],
|
||||
'stocks' => ['branch_id' => $branch->id, 'where' => ['business_id' => $business_id]],
|
||||
'product_settings' => ['branch_id' => $branch->id],
|
||||
'sale_returns' => ['branch_id' => $branch->id],
|
||||
'purchase_returns' => ['branch_id' => $branch->id],
|
||||
'expenses' => ['branch_id' => $branch->id],
|
||||
'incomes' => ['branch_id' => $branch->id],
|
||||
'sales' => ['branch_id' => $branch->id],
|
||||
'purchases' => ['branch_id' => $branch->id],
|
||||
'due_collects' => ['branch_id' => $branch->id],
|
||||
'parties' => ['branch_id' => $branch->id],
|
||||
'combo_products' => ['branch_id' => $branch->id],
|
||||
'transactions' => ['branch_id' => $branch->id],
|
||||
];
|
||||
|
||||
foreach ($updates as $table => $data) {
|
||||
$query = DB::table($table);
|
||||
if (!empty($data['where'])) {
|
||||
$query->where($data['where']);
|
||||
unset($data['where']);
|
||||
}
|
||||
$query->update($data);
|
||||
}
|
||||
|
||||
if (moduleCheck('HrmAddon')) {
|
||||
DB::table('holidays')->update(['branch_id' => $branch->id]);
|
||||
DB::table('attendances')->update(['branch_id' => $branch->id]);
|
||||
DB::table('leaves')->update(['branch_id' => $branch->id]);
|
||||
DB::table('payrolls')->update(['branch_id' => $branch->id]);
|
||||
DB::table('employees')->update(['branch_id' => $branch->id]);
|
||||
}
|
||||
|
||||
if (moduleCheck('WarehouseAddon')) {
|
||||
DB::table('warehouses')->update(['branch_id' => $branch->id]);
|
||||
DB::table('transfers')->update([
|
||||
'from_branch_id' => $branch->id,
|
||||
'to_branch_id' => $branch->id
|
||||
]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function get_root_domain()
|
||||
{
|
||||
$appUrl = config('app.url');
|
||||
return parse_url($appUrl, PHP_URL_HOST);
|
||||
}
|
||||
|
||||
function checkDomainStatus($domain)
|
||||
{
|
||||
$result = [
|
||||
'domain' => $domain,
|
||||
'exists' => false,
|
||||
'http' => false,
|
||||
'https' => false,
|
||||
];
|
||||
|
||||
// 1. Check if domain resolves (DNS record exists)
|
||||
if (dns_get_record($domain, DNS_A) || dns_get_record($domain, DNS_AAAA)) {
|
||||
$result['exists'] = true;
|
||||
|
||||
// 2. Check HTTP (port 80)
|
||||
try {
|
||||
$response = Http::timeout(5)->get("http://{$domain}");
|
||||
if ($response->successful()) {
|
||||
$result['http'] = true;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$result['http'] = false;
|
||||
}
|
||||
|
||||
// 3. Check HTTPS (port 443)
|
||||
try {
|
||||
$response = Http::timeout(5)->get("https://{$domain}");
|
||||
if ($response->successful()) {
|
||||
$result['https'] = true;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$result['https'] = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
function custom_reports()
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
if (moduleCheck('CustomReportsAddon')) {
|
||||
return cache_remember('custom-reports-' . $business_id, function () use ($business_id) {
|
||||
return Modules\CustomReportsAddon\App\Models\CustomReport::where('business_id', auth()->user()->business_id)->where('status', 1)->get();
|
||||
});
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function cash_balance()
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
if (!$businessId) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Sum of all credits and bank_to_cash
|
||||
$totalCredit = Transaction::where('business_id', $businessId)
|
||||
->where(function ($q) {
|
||||
$q->where('type', 'credit')
|
||||
->orWhere('transaction_type', 'bank_to_cash');
|
||||
})
|
||||
->sum('amount');
|
||||
|
||||
// Sum of all debits and cash_to_bank
|
||||
$totalDebit = Transaction::where('business_id', $businessId)
|
||||
->where(function ($q) {
|
||||
$q->where('type', 'debit')
|
||||
->orWhere('transaction_type', 'cash_to_bank');
|
||||
})
|
||||
->sum('amount');
|
||||
|
||||
return $totalCredit - $totalDebit;
|
||||
}
|
||||
|
||||
function transaction_types($transactions): string
|
||||
{
|
||||
if (!$transactions) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $transactions
|
||||
->map(function ($transaction) {
|
||||
if (
|
||||
$transaction->transaction_type === 'bank_payment' &&
|
||||
!empty($transaction->paymentType?->name)
|
||||
) {
|
||||
return $transaction->paymentType->name;
|
||||
}
|
||||
|
||||
return $transaction->transaction_type
|
||||
? ucfirst(explode('_', $transaction->transaction_type)[0])
|
||||
: '';
|
||||
})
|
||||
->filter()
|
||||
->unique()
|
||||
->implode(', ');
|
||||
}
|
||||
20
app/Http/Controllers/AboutController.php
Normal file
20
app/Http/Controllers/AboutController.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Plan;
|
||||
use App\Models\Option;
|
||||
use App\Models\Feature;
|
||||
|
||||
class AboutController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$page_data = get_option('manage-pages');
|
||||
$general = Option::where('key','general')->first();
|
||||
$features = Feature::whereStatus(1)->latest()->get();
|
||||
$plans = Plan::where('status',1)->latest()->get();
|
||||
|
||||
return view('web.about.index',compact('page_data','general','features','plans'));
|
||||
}
|
||||
}
|
||||
111
app/Http/Controllers/AcnooBusinessController.php
Normal file
111
app/Http/Controllers/AcnooBusinessController.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Business;
|
||||
use App\Models\PaymentType;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\BusinessCategory;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Cookie;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Modules\AffiliateAddon\App\Models\Affiliate;
|
||||
|
||||
class AcnooBusinessController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$categories = BusinessCategory::select('id', 'name')->whereStatus(1)->get();
|
||||
return response()->json($categories);
|
||||
}
|
||||
|
||||
public function getBusinessCategories()
|
||||
{
|
||||
$categories = BusinessCategory::select('id', 'name')->whereStatus(1)->get();
|
||||
return response()->json($categories);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validate_data = $request->validate([
|
||||
'companyName' => 'required|max:250',
|
||||
'business_category_id' => 'required|exists:business_categories,id',
|
||||
'plan_id' => 'required|exists:plans,id',
|
||||
'address' => 'nullable|max:250',
|
||||
'password' => 'required|min:6|max:100',
|
||||
'email' => 'required|email|unique:users,email',
|
||||
]);
|
||||
|
||||
if (moduleCheck('AffiliateAddon')) {
|
||||
$refCode = Cookie::get('ref_code');
|
||||
if ($refCode) {
|
||||
$affiliator = Affiliate::where('ref_code', $refCode)->first();
|
||||
if ($affiliator) {
|
||||
$validate_data['affiliator_id'] = $affiliator->user_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$business = Business::create($validate_data);
|
||||
|
||||
PaymentType::create([
|
||||
'name' => "Cash",
|
||||
'business_id' => $business->id
|
||||
]);
|
||||
|
||||
Session::put('plan_id', $request->plan_id);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Business created successfully.',
|
||||
'redirect' => route('payments-gateways.index', ['plan_id' => $request->plan_id, 'business_id' => $business->id]),
|
||||
]);
|
||||
}
|
||||
|
||||
public function verifyCode(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'email' => 'required|email',
|
||||
'otp' => 'required|min:4|max:15',
|
||||
]);
|
||||
|
||||
$user = User::where('email', $request->email)->first();
|
||||
|
||||
if (!$user) {
|
||||
return response()->json([
|
||||
'status' => 404,
|
||||
'message' => __('User not found'),
|
||||
], 404);
|
||||
}
|
||||
|
||||
if ($user->remember_token == $request->otp) {
|
||||
if ($user->email_verified_at > now()) {
|
||||
|
||||
Auth::login($user);
|
||||
$is_setup = $user->business_id ? true : false;
|
||||
$token = $user->createToken('createToken')->plainTextToken;
|
||||
$accessToken = $user->createToken('createToken');
|
||||
$this->setAccessTokenExpiration($accessToken);
|
||||
|
||||
$user->update([
|
||||
'remember_token' => NULL,
|
||||
'email_verified_at' => now(),
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Logged In successfully!',
|
||||
'is_setup' => $is_setup,
|
||||
'token' => $token,
|
||||
]);
|
||||
} else {
|
||||
return response()->json([
|
||||
'error' => __('The verification otp has been expired.')
|
||||
], 400);
|
||||
}
|
||||
} else {
|
||||
return response()->json([
|
||||
'error' => __('Invalid otp.')
|
||||
], 404);
|
||||
}
|
||||
}
|
||||
}
|
||||
70
app/Http/Controllers/Admin/AcnooAffiliateController.php
Normal file
70
app/Http/Controllers/Admin/AcnooAffiliateController.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Plan;
|
||||
use App\Models\Gateway;
|
||||
use App\Models\Business;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Modules\AffiliateAddon\App\Models\Affiliate;
|
||||
|
||||
class AcnooAffiliateController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$plans = Plan::latest()->get();
|
||||
$gateways = Gateway::latest()->get();
|
||||
$affiliates = Affiliate::with(['user:id,business_id,name,email','user.business:id,plan_subscribe_id,will_expire,companyName,phoneNumber,address,subscriptionDate,created_at,business_category_id:id,name','user.business.enrolled_plan:id,plan_id,business_id,plan_id','user.business.enrolled_plan.plan:id,subscriptionName'])->latest()->paginate(20);
|
||||
return view('admin.affiliate-modules.affiliate.index', compact('affiliates','plans','gateways'));
|
||||
}
|
||||
|
||||
public function acnooFilter(Request $request)
|
||||
{
|
||||
$search = $request->input('search');
|
||||
|
||||
$affiliates = Affiliate::with(['user:id,business_id,name,email','user.business:id,plan_subscribe_id,will_expire,companyName,phoneNumber,address,subscriptionDate,created_at,business_category_id:id,name','user.business.enrolled_plan:id,plan_id,business_id,plan_id','user.business.enrolled_plan.plan:id,subscriptionName'])->when($search, function ($q) use ($search) {
|
||||
$q->where(function ($q) use ($search) {
|
||||
$q->where('balance', 'like', '%' . $search . '%')
|
||||
->orWhereHas('user', function ($q) use ($search) {
|
||||
$q->where('name', 'like', '%' . $search . '%')
|
||||
->orwhere('email', 'like', '%' . $search . '%');
|
||||
})
|
||||
->orWhereHas('user.business.enrolled_plan.plan', function ($q) use ($search) {
|
||||
$q->where('subscriptionName', 'like', '%' . $search . '%');
|
||||
});
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20);
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('admin.affiliate-modules.affiliate.datas', compact('affiliates'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect(url()->previous());
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
Affiliate::findOrFail($id)->delete();
|
||||
return response()->json([
|
||||
'message' => __('Affiliate deleted successfully'),
|
||||
'redirect' => route('admin.affiliates.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
Affiliate::whereIn('id', $request->ids)->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Selected Affiliate deleted successfully'),
|
||||
'redirect' => route('admin.affiliates.index')
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Business;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AcnooAffiliateReportController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$items = Business::with(['enrolled_plan:id,plan_id', 'enrolled_plan.plan:id,subscriptionName', 'category:id,name'])->latest()->paginate(20);
|
||||
return view('admin.affiliate-modules.reports.index', compact('items'));
|
||||
}
|
||||
|
||||
public function acnooFilter(Request $request)
|
||||
{
|
||||
$search = $request->input('search');
|
||||
|
||||
$items = Business::with(['enrolled_plan:id,plan_id', 'enrolled_plan.plan:id,subscriptionName', 'category:id,name'])->when($search, function ($q) use ($search) {
|
||||
$q->where(function ($q) use ($search) {
|
||||
$q->where('companyName', 'like', '%' . $search . '%')
|
||||
->orWhereHas('enrolled_plan.plan', function ($q) use ($search) {
|
||||
$q->where('subscriptionName', 'like', '%' . $search . '%');
|
||||
});
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20);
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('admin.affiliate-modules.reports.datas', compact('items'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect(url()->previous());
|
||||
}
|
||||
}
|
||||
137
app/Http/Controllers/Admin/AcnooBannerController.php
Normal file
137
app/Http/Controllers/Admin/AcnooBannerController.php
Normal file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Banner;
|
||||
use App\Helpers\HasUploader;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class AcnooBannerController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('permission:banners-create')->only('create', 'store');
|
||||
$this->middleware('permission:banners-read')->only('index');
|
||||
$this->middleware('permission:banners-update')->only('edit', 'update','status');
|
||||
$this->middleware('permission:banners-delete')->only('destroy','deleteAll');
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$banners = Banner::latest()->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('admin.banners.search', compact('banners'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('admin.banners.index', compact('banners'));
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return view('admin.banners.create');
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'status' => 'nullable|in:on',
|
||||
'imageUrl' => 'required|image|mimes:jpeg,png,jpg,gif,svg',
|
||||
]);
|
||||
|
||||
Banner::create([
|
||||
'imageUrl' => $request->imageUrl ? $this->upload($request, 'imageUrl') : NULL,
|
||||
'status' => $request->status ? 1 : 0,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Banner saved successfully'),
|
||||
'redirect' => route('admin.banners.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(string $id)
|
||||
{
|
||||
$banners = Banner::findOrFail($id);
|
||||
return view('admin.banners.search',compact('banners'));
|
||||
}
|
||||
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
$request->validate([
|
||||
'status' => 'nullable|in:on',
|
||||
'imageUrl' => 'nullable|image|mimes:jpeg,png,jpg,gif,svg',
|
||||
]);
|
||||
|
||||
$banner = Banner::findOrFail($id);
|
||||
|
||||
$banner->update([
|
||||
'imageUrl' => $request->imageUrl ? $this->upload($request, 'imageUrl', $banner->imageUrl) : $banner->imageUrl,
|
||||
'status' => $request->status ? 1 : 0,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Banner updated successfully'),
|
||||
'redirect' => route('admin.banners.index')
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function destroy(string $id)
|
||||
{
|
||||
$banner = Banner::findOrFail($id);
|
||||
|
||||
if (file_exists($banner->imageUrl)) {
|
||||
Storage::delete($banner->imageUrl);
|
||||
}
|
||||
|
||||
$banner->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Banners deleted successfully'),
|
||||
'redirect' => route('admin.banners.index')
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
public function status(Request $request, $id)
|
||||
{
|
||||
$banner = Banner::findOrFail($id);
|
||||
$banner->update(['status' => $request->status]);
|
||||
return response()->json(['message' => 'Banner']);
|
||||
}
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
$idsToDelete = $request->input('ids');
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$banners = Banner::whereIn('id', $idsToDelete)->get();
|
||||
foreach ($banners as $banner) {
|
||||
if (file_exists($banner->imageUrl)) {
|
||||
Storage::delete($banner->imageUrl);
|
||||
}
|
||||
}
|
||||
|
||||
Banner::whereIn('id', $idsToDelete)->delete();
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Selected Banners deleted successfully'),
|
||||
'redirect' => route('admin.banners.index')
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json(__('Something went wrong.'), 400);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
140
app/Http/Controllers/Admin/AcnooBlogController.php
Normal file
140
app/Http/Controllers/Admin/AcnooBlogController.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Blog;
|
||||
use App\Models\Comment;
|
||||
use App\Helpers\HasUploader;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class AcnooBlogController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$blogs = Blog::when($request->search, function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('title', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})->latest()->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('admin.website-setting.blogs.datas', compact('blogs'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('admin.website-setting.blogs.index', compact('blogs'));
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return view('admin.website-setting.blogs.create');
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'title' => 'required|unique:blogs,title',
|
||||
'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg',
|
||||
'status' => 'boolean',
|
||||
'descriptions' => 'nullable|string',
|
||||
'tags' => 'nullable|array',
|
||||
'meta.title' => 'nullable|string',
|
||||
'meta.description' => 'nullable|string',
|
||||
]);
|
||||
|
||||
Blog::create($request->except('image') + [
|
||||
'user_id' => Auth::id(),
|
||||
'image' => $request->image ? $this->upload($request, 'image') : null,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('BLog created successfully'),
|
||||
'redirect' => route('admin.blogs.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(Blog $blog)
|
||||
{
|
||||
return view('admin.website-setting.blogs.edit', compact('blog'));
|
||||
}
|
||||
|
||||
public function update(Request $request, Blog $blog)
|
||||
{
|
||||
|
||||
$request->validate([
|
||||
'title' => 'required|unique:blogs,title,' . $blog->id,
|
||||
'image' => 'nullable|image|mimes:jpeg,png,jpg,gif,svg',
|
||||
'status' => 'boolean',
|
||||
'descriptions' => 'nullable|string',
|
||||
'tags' => 'nullable|array',
|
||||
'meta.title' => 'nullable|string',
|
||||
'meta.description' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$blog->update($request->except('image') + [
|
||||
'user_id' => Auth::id(),
|
||||
'image' => $request->image ? $this->upload($request, 'image', $blog->image) : $blog->image,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('BLog updated successfully'),
|
||||
'redirect' => route('admin.blogs.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(Blog $blog)
|
||||
{
|
||||
if (file_exists($blog->image)) {
|
||||
Storage::delete($blog->image);
|
||||
}
|
||||
|
||||
$blog->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Blog deleted successfully'),
|
||||
'redirect' => route('admin.blogs.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function status(Request $request, $id)
|
||||
{
|
||||
$blog_status = Blog::findOrFail($id);
|
||||
$blog_status->update(['status' => $request->status]);
|
||||
return response()->json(['message' => 'Blog']);
|
||||
}
|
||||
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
Blog::whereIn('id', $request->ids)->delete();
|
||||
return response()->json([
|
||||
'message' => __('Selected Blog deleted successfully'),
|
||||
'redirect' => route('admin.blogs.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function filterComment($id, Request $request)
|
||||
{
|
||||
$blog = Blog::findOrFail($id);
|
||||
$comments = Comment::with('blog:id')->whereStatus(1)->where('blog_id', $blog->id)->when($request->search, function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%')
|
||||
->orwhere('email', 'like', '%' . $request->search . '%')
|
||||
->orwhere('comment', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})->latest()->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('admin.website-setting.blogs.comments.datas', compact('comments','blog'))->render()
|
||||
]);
|
||||
}
|
||||
return view('admin.website-setting.blogs.comments.index', compact('comments','blog'));
|
||||
}
|
||||
}
|
||||
105
app/Http/Controllers/Admin/AcnooBusinessCategoryController.php
Normal file
105
app/Http/Controllers/Admin/AcnooBusinessCategoryController.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\BusinessCategory;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AcnooBusinessCategoryController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$categories = BusinessCategory::when($request->search, function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('description', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})->latest()->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('admin.business-categories.datas', compact('categories'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('admin.business-categories.index', compact('categories'));
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return view('admin.business-categories.create');
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
|
||||
$request->validate([
|
||||
'status' => 'nullable|in:on',
|
||||
'description' => 'nullable|string|max:255',
|
||||
'name' => 'required|string|unique:business_categories|max:255',
|
||||
]);
|
||||
|
||||
BusinessCategory::create($request->except('status') + [
|
||||
'status' => $request->status ? 1 : 0,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Category saved successfully'),
|
||||
'redirect' => route('admin.business-categories.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
$category = BusinessCategory::find($id);
|
||||
return view('admin.business-categories.edit', compact('category'));
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$request->validate([
|
||||
'status' => 'in:on',
|
||||
'description' => 'nullable|string|max:255',
|
||||
'name' => 'required|string|max:255|unique:business_categories,name,' . $id,
|
||||
]);
|
||||
|
||||
$category = BusinessCategory::find($id);
|
||||
|
||||
$category->update($request->except('status') + [
|
||||
'status' => $request->status ? 1 : 0,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Category updated successfully'),
|
||||
'redirect' => route('admin.business-categories.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
$category = BusinessCategory::findOrFail($id);
|
||||
$category->delete();
|
||||
return response()->json([
|
||||
'message' => __('Category deleted successfully'),
|
||||
'redirect' => route('admin.business-categories.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
BusinessCategory::whereIn('id', $request->ids)->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Category deleted successfully'),
|
||||
'redirect' => route('admin.business-categories.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function status(Request $request, $id)
|
||||
{
|
||||
$category = BusinessCategory::findOrFail($id);
|
||||
$category->update(['status' => $request->status]);
|
||||
return response()->json(['message' => 'Business category']);
|
||||
}
|
||||
}
|
||||
347
app/Http/Controllers/Admin/AcnooBusinessController.php
Normal file
347
app/Http/Controllers/Admin/AcnooBusinessController.php
Normal file
@@ -0,0 +1,347 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Plan;
|
||||
use App\Models\User;
|
||||
use App\Models\Gateway;
|
||||
use App\Models\Business;
|
||||
use App\Models\PaymentType;
|
||||
use App\Helpers\HasUploader;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\PlanSubscribe;
|
||||
use App\Models\BusinessCategory;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Modules\AffiliateAddon\App\Models\Affiliate;
|
||||
use Modules\AffiliateAddon\App\Models\AffiliateTransaction;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class AcnooBusinessController extends Controller
|
||||
{
|
||||
|
||||
use HasUploader;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('permission:business-create')->only('create', 'store');
|
||||
$this->middleware('permission:business-read')->only('index');
|
||||
$this->middleware('permission:business-update')->only('edit', 'update', 'status');
|
||||
$this->middleware('permission:business-delete')->only('destroy', 'deleteAll');
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$plans = Plan::latest()->get();
|
||||
$gateways = Gateway::latest()->get();
|
||||
|
||||
$search = $request->input('search');
|
||||
|
||||
$businesses = Business::with(['enrolled_plan:id,plan_id', 'enrolled_plan.plan:id,subscriptionName', 'category:id,name'])
|
||||
->when($request->search, function ($q) use ($search) {
|
||||
$q->where(function ($q) use ($search) {
|
||||
$q->where('companyName', 'like', '%' . $search . '%')
|
||||
->orWhere('phoneNumber', 'like', '%' . $search . '%')
|
||||
->orWhereHas('category', function ($q) use ($search) {
|
||||
$q->where('name', 'like', '%' . $search . '%');
|
||||
})
|
||||
->orWhereHas('user', function ($q) use ($search) {
|
||||
$q->where('email', 'like', '%' . $search . '%');
|
||||
})
|
||||
->orWhereHas('enrolled_plan.plan', function ($q) use ($search) {
|
||||
$q->where('subscriptionName', 'like', '%' . $search . '%');
|
||||
});
|
||||
});
|
||||
})->latest()->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('admin.business.datas', compact('businesses'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('admin.business.index', compact('businesses', 'gateways', 'plans'));
|
||||
}
|
||||
|
||||
|
||||
public function create()
|
||||
{
|
||||
$plans = Plan::where('status', 1)->latest()->get();
|
||||
$categories = BusinessCategory::latest()->get();
|
||||
return view('admin.business.create', compact('plans', 'categories'));
|
||||
}
|
||||
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'address' => 'nullable|max:250',
|
||||
'companyName' => 'required|max:250',
|
||||
'email' => 'required|email|unique:users',
|
||||
'password' => 'required|string|min:4|confirmed',
|
||||
'pictureUrl' => 'nullable|image',
|
||||
'phoneNumber' => 'nullable',
|
||||
'shopOpeningBalance' => 'nullable|numeric',
|
||||
'business_category_id' => 'required|exists:business_categories,id',
|
||||
'plan_subscribe_id' => 'nullable|exists:plans,id',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
|
||||
$user = auth()->user();
|
||||
|
||||
$business = Business::create([
|
||||
'companyName' => $request->companyName,
|
||||
'address' => $request->address,
|
||||
'email' => $request->email,
|
||||
'phoneNumber' => $request->phoneNumber,
|
||||
'shopOpeningBalance' => $request->shopOpeningBalance,
|
||||
'business_category_id' => $request->business_category_id,
|
||||
'pictureUrl' => $request->pictureUrl ? $this->upload($request, 'pictureUrl') : NULL,
|
||||
'user_id' => $user->id,
|
||||
]);
|
||||
|
||||
PaymentType::create([
|
||||
'name' => "Cash",
|
||||
'business_id' => $business->id
|
||||
]);
|
||||
|
||||
User::create([
|
||||
'business_id' => $business->id,
|
||||
'name' => $request->companyName,
|
||||
'email' => $request->email,
|
||||
'phone' => $request->phoneNumber,
|
||||
'image' => $request->pictureUrl ? $this->upload($request, 'pictureUrl') : NULL,
|
||||
'password' => Hash::make($request->password),
|
||||
'user_id' => $user->id,
|
||||
]);
|
||||
|
||||
if ($request->plan_subscribe_id) {
|
||||
$plan = Plan::findOrFail($request->plan_subscribe_id);
|
||||
|
||||
$subscribe = PlanSubscribe::create([
|
||||
'plan_id' => $plan->id,
|
||||
'notes' => $request->notes,
|
||||
'duration' => $plan->duration,
|
||||
'business_id' => $business->id,
|
||||
'price' => $plan->subscriptionPrice,
|
||||
'gateway_id' => $request->gateway_id,
|
||||
'allow_multibranch' => $plan->allow_multibranch,
|
||||
'addon_domain_limit' => $plan->addon_domain_limit ?? 0,
|
||||
'subdomain_limit' => $plan->subdomain_limit ?? 0,
|
||||
]);
|
||||
|
||||
$business->update([
|
||||
'subscriptionDate' => now(),
|
||||
'plan_subscribe_id' => $subscribe->id,
|
||||
'will_expire' => now()->addDays($plan->duration),
|
||||
]);
|
||||
|
||||
sendNotification($subscribe->id, route('admin.subscription-reports.index', ['id' => $subscribe->id]), __('Plan subscribed by ' . $user->name));
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Business created successfully.'),
|
||||
'redirect' => route('admin.business.index'),
|
||||
]);
|
||||
} catch (\Throwable $th) {
|
||||
DB::rollback();
|
||||
return response()->json(__('Something went wrong.'), 403);
|
||||
}
|
||||
}
|
||||
|
||||
public function edit(string $id)
|
||||
{
|
||||
$plans = Plan::latest()->get();
|
||||
$business = Business::findOrFail($id);
|
||||
$categories = BusinessCategory::latest()->get();
|
||||
$user = User::where('business_id', $business->id)->firstOrFail();
|
||||
return view('admin.business.edit', compact('business', 'plans', 'categories', 'user'));
|
||||
}
|
||||
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
|
||||
$business = Business::findOrFail($id);
|
||||
$user = User::where('business_id', $business->id)->firstOrFail();
|
||||
|
||||
$request->validate([
|
||||
'address' => 'nullable|max:250',
|
||||
'companyName' => 'required|max:250',
|
||||
'email' => [
|
||||
'required',
|
||||
'email',
|
||||
Rule::unique('users', 'email')->ignore($user->id),
|
||||
],
|
||||
'password' => 'nullable|string|min:4|confirmed',
|
||||
'pictureUrl' => 'nullable|image',
|
||||
'phoneNumber' => 'nullable',
|
||||
'shopOpeningBalance' => 'nullable|numeric',
|
||||
'business_category_id' => 'required|exists:business_categories,id',
|
||||
'plan_subscribe_id' => 'nullable|exists:plans,id',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
|
||||
$business->update([
|
||||
'companyName' => $request->companyName,
|
||||
'address' => $request->address,
|
||||
'email' => $request->email,
|
||||
'phoneNumber' => $request->phoneNumber,
|
||||
'shopOpeningBalance' => $request->shopOpeningBalance,
|
||||
'business_category_id' => $request->business_category_id,
|
||||
'pictureUrl' => $request->pictureUrl ? $this->upload($request, 'pictureUrl', $business->pictureUrl) : $business->pictureUrl,
|
||||
]);
|
||||
|
||||
$user->update([
|
||||
'name' => $request->companyName,
|
||||
'email' => $request->email,
|
||||
'phone' => $request->phoneNumber,
|
||||
'image' => $request->pictureUrl ? $this->upload($request, 'pictureUrl') : $user->image,
|
||||
'password' => $request->password ? Hash::make($request->password) : $user->password,
|
||||
]);
|
||||
|
||||
$prev_subscription = PlanSubscribe::where('business_id', $business->id)->latest()->first();
|
||||
|
||||
if ($request->plan_subscribe_id && ($prev_subscription->plan_id != $request->plan_subscribe_id)) {
|
||||
$plan = Plan::findOrFail($request->plan_subscribe_id);
|
||||
$subscribe = PlanSubscribe::create([
|
||||
'plan_id' => $plan->id,
|
||||
'notes' => $request->notes,
|
||||
'duration' => $plan->duration,
|
||||
'business_id' => $business->id,
|
||||
'price' => $plan->subscriptionPrice,
|
||||
'gateway_id' => $request->gateway_id,
|
||||
'allow_multibranch' => $plan->allow_multibranch,
|
||||
'addon_domain_limit' => $plan->addon_domain_limit ?? 0,
|
||||
'subdomain_limit' => $plan->subdomain_limit ?? 0,
|
||||
]);
|
||||
|
||||
$business->update([
|
||||
'subscriptionDate' => now(),
|
||||
'plan_subscribe_id' => $subscribe->id,
|
||||
'will_expire' => now()->addDays($plan->duration),
|
||||
]);
|
||||
|
||||
sendNotification($subscribe->id, route('admin.subscription-reports.index', ['id' => $subscribe->id]), __('Plan subscribed by ' . auth()->user()->name));
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Business updated successfully.'),
|
||||
'redirect' => route('admin.business.index'),
|
||||
]);
|
||||
} catch (\Throwable $th) {
|
||||
DB::rollback();
|
||||
return response()->json(__('Something went wrong.'), 403);
|
||||
}
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
$business = Business::findOrFail($id);
|
||||
$business->delete();
|
||||
return response()->json([
|
||||
'message' => __('Business deleted successfully'),
|
||||
'redirect' => route('admin.business.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
Business::whereIn('id', $request->ids)->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Selected Business deleted successfully'),
|
||||
'redirect' => route('admin.business.index')
|
||||
]);
|
||||
}
|
||||
|
||||
// Upgrade plan code
|
||||
|
||||
public function upgradePlan(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'price' => 'required|string',
|
||||
'notes' => 'required|string',
|
||||
'plan_id' => 'required|exists:plans,id',
|
||||
'business_id' => 'required|exists:businesses,id',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
|
||||
$plan = Plan::findOrFail($request->plan_id);
|
||||
$business = Business::findOrFail($request->business_id);
|
||||
|
||||
$subscribe = PlanSubscribe::create([
|
||||
'plan_id' => $plan->id,
|
||||
'payment_status' => 'paid',
|
||||
'notes' => $request->notes,
|
||||
'duration' => $plan->duration,
|
||||
'business_id' => $business->id,
|
||||
'price' => $plan->subscriptionPrice,
|
||||
'gateway_id' => $request->gateway_id,
|
||||
'allow_multibranch' => $plan->allow_multibranch,
|
||||
'addon_domain_limit' => $plan->addon_domain_limit ?? 0,
|
||||
'subdomain_limit' => $plan->subdomain_limit ?? 0
|
||||
]);
|
||||
|
||||
Cache::forget('plan-data-' . $business->id);
|
||||
|
||||
$business->update([
|
||||
'subscriptionDate' => now(),
|
||||
'plan_subscribe_id' => $subscribe->id,
|
||||
'will_expire' => now()->addDays($plan->duration),
|
||||
]);
|
||||
|
||||
if (moduleCheck('AffiliateAddon') && $business->affiliator_id) {
|
||||
$affiliateUser = User::find($business->affiliator_id);
|
||||
|
||||
if ($affiliateUser && $plan->affiliate_commission > 0) {
|
||||
$commission = ($plan->subscriptionPrice * $plan->affiliate_commission) / 100;
|
||||
|
||||
Affiliate::where('user_id', $affiliateUser->id)->increment('balance', $commission);
|
||||
|
||||
AffiliateTransaction::create([
|
||||
'user_id' => $affiliateUser->id,
|
||||
'business_id' => $business->id,
|
||||
'trx' => strtoupper(str()->random(10)),
|
||||
'type' => 'credit',
|
||||
'amount' => $commission,
|
||||
'title' => 'Commission from Order #' . $subscribe->id,
|
||||
'reference_id' => $subscribe->id,
|
||||
'reference_type' => 'PlanSubscribe',
|
||||
'note' => 'User purchased via your referral link',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
sendNotification($subscribe->id, route('admin.subscription-reports.index', ['id' => $subscribe->id]), __('Plan subscribed by ' . auth()->user()->name));
|
||||
|
||||
DB::commit();
|
||||
return response()->json([
|
||||
'message' => __('Subscription enrolled successfully.'),
|
||||
'redirect' => route('admin.subscription-reports.index'),
|
||||
]);
|
||||
} catch (\Throwable $th) {
|
||||
DB::rollback();
|
||||
return response()->json(__('Something went wrong.'), 403);
|
||||
}
|
||||
}
|
||||
|
||||
public function status(Request $request, $id)
|
||||
{
|
||||
$business = Business::findOrFail($id);
|
||||
$business->update(['status' => $request->status]);
|
||||
return response()->json(['message' => 'Business']);
|
||||
}
|
||||
}
|
||||
28
app/Http/Controllers/Admin/AcnooCommentController.php
Normal file
28
app/Http/Controllers/Admin/AcnooCommentController.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Comment;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AcnooCommentController extends Controller
|
||||
{
|
||||
public function destroy(Comment $comment)
|
||||
{
|
||||
$comment->delete();
|
||||
return response()->json([
|
||||
'message' => __('Comment deleted successfully.'),
|
||||
'redirect' => route('admin.blogs.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
Comment::whereIn('id', $request->ids)->delete();
|
||||
return response()->json([
|
||||
'message' => __('Selected Comments deleted successfully'),
|
||||
'redirect' => route('admin.blogs.index')
|
||||
]);
|
||||
}
|
||||
}
|
||||
150
app/Http/Controllers/Admin/AcnooCurrencyController.php
Normal file
150
app/Http/Controllers/Admin/AcnooCurrencyController.php
Normal file
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Currency;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AcnooCurrencyController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('permission:currencies-create')->only('create', 'store');
|
||||
$this->middleware('permission:currencies-read')->only('index');
|
||||
$this->middleware('permission:currencies-update')->only('edit', 'update', 'default');
|
||||
$this->middleware('permission:currencies-delete')->only('destroy');
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$currencies = Currency::orderBy('is_default', 'desc')->orderBy('status', 'desc')->when($request->search, function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('country_name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('code', 'like', '%' . $request->search . '%')
|
||||
->orWhere('symbol', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})->latest()->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('admin.currencies.datas', compact('currencies'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('admin.currencies.index', compact('currencies'));
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
$countries = base_path('lang/countrylist.json');
|
||||
$countries = json_decode(file_get_contents($countries), true);
|
||||
return view('admin.currencies.create', compact('countries'));
|
||||
}
|
||||
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|unique:currencies',
|
||||
'country_name' => 'nullable|string',
|
||||
'code' => 'required|string|unique:currencies',
|
||||
'rate' => 'nullable|numeric',
|
||||
'symbol' => 'nullable|string',
|
||||
'position' => 'nullable|string',
|
||||
'status' => 'required|integer',
|
||||
'is_default' => 'nullable|boolean',
|
||||
]);
|
||||
|
||||
Currency::create($request->all());
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Currency Created successfully'),
|
||||
'redirect' => route('admin.currencies.index')
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function edit(Currency $currency)
|
||||
{
|
||||
$countries = base_path('lang/countrylist.json');
|
||||
$countries = json_decode(file_get_contents($countries), true);
|
||||
return view('admin.currencies.edit', compact('currency', 'countries'));
|
||||
}
|
||||
|
||||
public function update(Request $request, Currency $currency)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|unique:currencies,name,' . $currency->id,
|
||||
'country_name' => 'nullable|string',
|
||||
'code' => 'required|string|unique:currencies,code,' . $currency->id,
|
||||
'rate' => 'nullable|numeric',
|
||||
'symbol' => 'nullable|string',
|
||||
'position' => 'nullable|string',
|
||||
'status' => 'required|integer',
|
||||
'is_default' => 'nullable|boolean',
|
||||
]);
|
||||
|
||||
$currency->update($request->all());
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Currency updated successfully'),
|
||||
'redirect' => route('admin.currencies.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function default($id)
|
||||
{
|
||||
$currency = Currency::find($id);
|
||||
|
||||
if ($currency) {
|
||||
Currency::where('id', '!=', $id)->update(['is_default' => 0]);
|
||||
$currency->update(['is_default' => 1]);
|
||||
cache()->forget('default_currency');
|
||||
}
|
||||
|
||||
return redirect()->route('admin.currencies.index')->with('message', __('Default currency activated successfully'));
|
||||
}
|
||||
|
||||
public function destroy(Currency $currency)
|
||||
{
|
||||
if ($currency->is_default) {
|
||||
return response()->json([
|
||||
'message' => __('You cannot delete it because it is default currency'),
|
||||
'redirect' => route('admin.currencies.index')
|
||||
], 400);
|
||||
}
|
||||
|
||||
$currency->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Currency deleted successfully'),
|
||||
'redirect' => route('admin.currencies.index')
|
||||
], 200);
|
||||
}
|
||||
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
$default_currency_id = Currency::where('is_default', 1)->value('id');
|
||||
|
||||
if (count($request->ids) === 1 && in_array($default_currency_id, $request->ids)) {
|
||||
return response()->json([
|
||||
'message' => __('You cannot delete the default currency.'),
|
||||
'redirect' => route('admin.currencies.index')
|
||||
], 400);
|
||||
}
|
||||
|
||||
$idsToDelete = array_filter($request->ids, function ($id) use ($default_currency_id) {
|
||||
return $id != $default_currency_id;
|
||||
});
|
||||
|
||||
Currency::whereIn('id', $idsToDelete)->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Selected currencies deleted successfully.'),
|
||||
'redirect' => route('admin.currencies.index')
|
||||
]);
|
||||
}
|
||||
}
|
||||
117
app/Http/Controllers/Admin/AcnooFeatureController.php
Normal file
117
app/Http/Controllers/Admin/AcnooFeatureController.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Feature;
|
||||
use App\Helpers\HasUploader;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class AcnooFeatureController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$features = Feature::when($request->search, function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('title', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})->latest()->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('admin.website-setting.features.datas', compact('features'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('admin.website-setting.features.index', compact('features'));
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return view('admin.website-setting.features.create');
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'status' => 'required',
|
||||
'title' => 'required',
|
||||
'bg_color' => 'required',
|
||||
'image' => 'nullable|image|mimes:jpeg,png,jpg,gif',
|
||||
]);
|
||||
|
||||
Feature::create($request->except('image') + [
|
||||
'image' => $request->image ? $this->upload($request, 'image') : NULL
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Feature created successfully'),
|
||||
'redirect' => route('admin.features.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(Feature $feature)
|
||||
{
|
||||
return view('admin.website-setting.features.edit', compact('feature'));
|
||||
}
|
||||
|
||||
public function update(Request $request, Feature $feature)
|
||||
{
|
||||
$request->validate([
|
||||
'status' => 'required',
|
||||
'title' => 'required|string',
|
||||
'bg_color' => 'required|string',
|
||||
'image' => 'nullable|image|mimes:jpeg,png,jpg,gif',
|
||||
]);
|
||||
|
||||
$feature->update($request->except('image') + [
|
||||
'image' => $request->image ? $this->upload($request, 'image', $feature->image) : $feature->image,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Feature updated successfully'),
|
||||
'redirect' => route('admin.features.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(Feature $feature)
|
||||
{
|
||||
if (file_exists($feature->image)) {
|
||||
Storage::delete($feature->image);
|
||||
}
|
||||
$feature->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Feature deleted successfully'),
|
||||
'redirect' => route('admin.features.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function status(Request $request, $id)
|
||||
{
|
||||
$feature = Feature::findOrFail($id);
|
||||
$feature->update(['status' => $request->status]);
|
||||
return response()->json(['message' => 'Feature ']);
|
||||
}
|
||||
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
$features = Feature::whereIn('id', $request->ids)->get();
|
||||
foreach ($features as $feature) {
|
||||
if (file_exists($feature->image)) {
|
||||
Storage::delete($feature->image);
|
||||
}
|
||||
}
|
||||
|
||||
$features->each->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Selected Feature deleted successfully'),
|
||||
'redirect' => route('admin.features.index')
|
||||
]);
|
||||
}
|
||||
}
|
||||
111
app/Http/Controllers/Admin/AcnooInterfaceController.php
Normal file
111
app/Http/Controllers/Admin/AcnooInterfaceController.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Helpers\HasUploader;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\PosAppInterface;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class AcnooInterfaceController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$interfaces = PosAppInterface::latest()->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('admin.website-setting.interfaces.datas', compact('interfaces'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('admin.website-setting.interfaces.index', compact('interfaces'));
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return view('admin.website-setting.interfaces.create');
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'status' => 'required',
|
||||
'image' => 'nullable|image|mimes:jpeg,png,jpg,gif',
|
||||
]);
|
||||
|
||||
PosAppInterface::create($request->except('image') + [
|
||||
'image' => $request->image ? $this->upload($request, 'image') : NULL
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Interfaces created successfully'),
|
||||
'redirect' => route('admin.interfaces.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
$interface = PosAppInterface::findOrFail($id);
|
||||
return view('admin.website-setting.interfaces.edit', compact('interface'));
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$interface = PosAppInterface::findOrFail($id);
|
||||
$request->validate([
|
||||
'status' => 'required',
|
||||
'image' => 'nullable|image|mimes:jpeg,png,jpg,gif',
|
||||
]);
|
||||
|
||||
$interface->update($request->except('image') + [
|
||||
'image' => $request->image ? $this->upload($request, 'image', $interface->image) : $interface->image,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Interface updated successfully'),
|
||||
'redirect' => route('admin.interfaces.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
$posAppInterface = PosAppInterface::findOrFail($id);
|
||||
if (file_exists($posAppInterface->image)) {
|
||||
Storage::delete($posAppInterface->image);
|
||||
}
|
||||
$posAppInterface->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Interface deleted successfully'),
|
||||
'redirect' => route('admin.interfaces.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function status(Request $request,$id)
|
||||
{
|
||||
$posAppInterface = PosAppInterface::findOrFail($id);
|
||||
$posAppInterface->update(['status' => $request->status]);
|
||||
return response()->json(['message' => 'Interface ']);
|
||||
}
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
$posAppInterfaces = PosAppInterface::whereIn('id', $request->ids)->get();
|
||||
foreach ($posAppInterfaces as $posAppInterface) {
|
||||
if (file_exists($posAppInterface->image)) {
|
||||
Storage::delete($posAppInterface->image);
|
||||
}
|
||||
}
|
||||
|
||||
$posAppInterfaces->each->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Selected Interface deleted successfully'),
|
||||
'redirect' => route('admin.interfaces.index')
|
||||
]);
|
||||
}
|
||||
}
|
||||
118
app/Http/Controllers/Admin/AcnooLanguageController.php
Normal file
118
app/Http/Controllers/Admin/AcnooLanguageController.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Language;
|
||||
use App\Helpers\HasUploader;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class AcnooLanguageController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
public function index(Request $request)
|
||||
{
|
||||
$languages = Language::when($request->has('search'), function ($q) use ($request) {
|
||||
$q->where(function ($query) use ($request) {
|
||||
$query->where('name', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})
|
||||
->latest();
|
||||
|
||||
if ($request->ajax()) {
|
||||
$languages = $languages->get();
|
||||
|
||||
return response()->json([
|
||||
'data' => view('admin.website-setting.languages.datas', compact('languages'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
$languages = $languages->paginate(20);
|
||||
return view('admin.website-setting.languages.index', compact('languages'));
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return view('admin.website-setting.languages.create');
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'status' => 'required',
|
||||
'name' => 'required|string',
|
||||
'icon' => 'nullable|image|mimes:jpeg,png,jpg,gif',
|
||||
]);
|
||||
|
||||
Language::create($request->except('icon') + [
|
||||
'icon' => $request->icon ? $this->upload($request, 'icon') : NULL
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Laguage created successfully'),
|
||||
'redirect' => route('admin.languages.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(Language $language)
|
||||
{
|
||||
return view('admin.website-setting.languages.edit', compact('language'));
|
||||
}
|
||||
|
||||
public function update(Request $request, Language $language)
|
||||
{
|
||||
$request->validate([
|
||||
'status' => 'required',
|
||||
'name' => 'required|string',
|
||||
'icon' => 'nullable|image|mimes:jpeg,png,jpg,gif',
|
||||
]);
|
||||
|
||||
$language->update($request->except('icon') + [
|
||||
'icon' => $request->icon ? $this->upload($request, 'icon', $language->icon) : $language->icon,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Language updated successfully'),
|
||||
'redirect' => route('admin.languages.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(Language $language)
|
||||
{
|
||||
if (file_exists($language->icon)) {
|
||||
Storage::delete($language->icon);
|
||||
}
|
||||
$language->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Language deleted successfully'),
|
||||
'redirect' => route('admin.languages.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function status(Request $request, $id)
|
||||
{
|
||||
$language = Language::findOrFail($id);
|
||||
$language->update(['status' => $request->status]);
|
||||
return response()->json(['message' => 'Language ']);
|
||||
}
|
||||
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
$languages = Language::whereIn('id', $request->ids)->get();
|
||||
foreach ($languages as $language) {
|
||||
if (file_exists($language->icon)) {
|
||||
Storage::delete($language->icon);
|
||||
}
|
||||
}
|
||||
|
||||
$languages->each->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Selected Language deleted successfully'),
|
||||
'redirect' => route('admin.languages.index')
|
||||
]);
|
||||
}
|
||||
}
|
||||
55
app/Http/Controllers/Admin/AcnooMessageController.php
Normal file
55
app/Http/Controllers/Admin/AcnooMessageController.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Message;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AcnooMessageController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('permission:messages-read')->only('index');
|
||||
$this->middleware('permission:messages-delete')->only('destroy');
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$messages = Message::when($request->search, function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('phone', 'like', '%' . $request->search . '%')
|
||||
->orWhere('email', 'like', '%' . $request->search . '%')
|
||||
->orWhere('company_name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('message', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})->latest()->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('admin.messages.datas', compact('messages'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('admin.messages.index', compact('messages'));
|
||||
}
|
||||
|
||||
public function destroy(Message $message)
|
||||
{
|
||||
$message->delete();
|
||||
return response()->json([
|
||||
'message' => __('Message deleted successfully'),
|
||||
'redirect' => route('admin.messages.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
Message::whereIn('id', $request->ids)->delete();
|
||||
return response()->json([
|
||||
'message' => __('Selected Mesages deleted successfully'),
|
||||
'redirect' => route('admin.messages.index')
|
||||
]);
|
||||
}
|
||||
}
|
||||
164
app/Http/Controllers/Admin/AcnooPlanController.php
Normal file
164
app/Http/Controllers/Admin/AcnooPlanController.php
Normal file
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Plan;
|
||||
use App\Models\PlanSubscribe;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class AcnooPlanController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('permission:plans-create')->only('create', 'store');
|
||||
$this->middleware('permission:plans-read')->only('index');
|
||||
$this->middleware('permission:plans-update')->only('edit', 'update', 'status');
|
||||
$this->middleware('permission:plans-delete')->only('destroy', 'deleteAll');
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$search = $request->input('search');
|
||||
|
||||
$plans = Plan::when($request->search, function ($q) use ($search) {
|
||||
$q->where(function ($q) use ($search) {
|
||||
$q->where('subscriptionName', 'like', '%' . $search . '%')
|
||||
->orWhere('duration', 'like', '%' . $search . '%')
|
||||
->orWhere('subscriptionPrice', 'like', '%' . $search . '%');
|
||||
});
|
||||
})->latest()->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('admin.plans.datas', compact('plans'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('admin.plans.index', compact('plans'));
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return view('admin.plans.create');
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'duration' => 'required|string',
|
||||
'offerPrice' => 'nullable|numeric|min:0|max:9999999999999',
|
||||
'subscriptionName' => 'required|string|max:255|unique:plans,subscriptionName',
|
||||
'subscriptionPrice' => 'required|numeric|min:0|max:9999999999999',
|
||||
'addon_domain_limit' => 'nullable|integer|min:0',
|
||||
'subdomain_limit' => 'nullable|integer|min:0',
|
||||
]);
|
||||
|
||||
Plan::create($request->except(['offerPrice', 'status', 'allow_multibranch']) + [
|
||||
'offerPrice' => $request->offerPrice ?? NULL,
|
||||
'status' => $request->status ? 1 : 0,
|
||||
'allow_multibranch' => $request->allow_multibranch ? 1 : 0,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Subscription Plan created successfully'),
|
||||
'redirect' => route('admin.plans.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(Plan $plan)
|
||||
{
|
||||
return view('admin.plans.edit', compact('plan'));
|
||||
}
|
||||
|
||||
public function update(Request $request, Plan $plan)
|
||||
{
|
||||
$request->validate([
|
||||
'duration' => 'required|string',
|
||||
'offerPrice' => 'nullable|numeric|min:0|max:9999999999999',
|
||||
'subscriptionPrice' => 'required|numeric|min:0|max:9999999999999',
|
||||
'subscriptionName' => 'required|string|max:255|unique:plans,subscriptionName,' . $plan->id,
|
||||
'addon_domain_limit' => 'nullable|integer|min:0',
|
||||
'subdomain_limit' => 'nullable|integer|min:0',
|
||||
]);
|
||||
|
||||
|
||||
if ($plan->subscriptionName == 'Free' && ($plan->subscriptionName != $request->subscriptionName || $plan->subscriptionPrice != $request->subscriptionPrice || $plan->offerPrice != $request->offerPrice)) {
|
||||
return response()->json([
|
||||
'message' => __('You can not change the package name & price of free plan.'),
|
||||
], 406);
|
||||
}
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$plan->update($request->except(['offerPrice', 'status', 'allow_multibranch']) + [
|
||||
'offerPrice' => $request->offerPrice ?? NULL,
|
||||
'status' => $request->status ? 1 : 0,
|
||||
'allow_multibranch' => $request->allow_multibranch ? 1 : 0,
|
||||
]);
|
||||
|
||||
if ($request->allow_existing_subscriber){
|
||||
$updateData = [
|
||||
'allow_multibranch' => $request->allow_multibranch ? 1 : 0,
|
||||
'addon_domain_limit' => $request->addon_domain_limit ?? 0,
|
||||
'subdomain_limit' => $request->subdomain_limit ?? 0,
|
||||
];
|
||||
|
||||
PlanSubscribe::where('plan_id', $plan->id)->update($updateData);
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Subscription Plan updated successfully'),
|
||||
'redirect' => route('admin.plans.index')
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
'message' => 'Something went wrong.',
|
||||
'error' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function status(Request $request, $id)
|
||||
{
|
||||
$plan = Plan::findOrFail($id);
|
||||
if ($plan->subscriptionName == 'Free') {
|
||||
return response()->json([
|
||||
'message' => __('You can not change the status for free plan.'),
|
||||
], 406);
|
||||
}
|
||||
$plan->update(['status' => $request->status]);
|
||||
return response()->json(['message' => 'Plan']);
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
$plan = Plan::findOrFail($id);
|
||||
if ($plan->subscriptionName == 'Free') {
|
||||
return response()->json([
|
||||
'message' => __('You can not delete free plan.'),
|
||||
], 406);
|
||||
}
|
||||
|
||||
$plan->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Subscription Plan deleted successfully'),
|
||||
'redirect' => route('admin.plans.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
Plan::whereIn('id', $request->ids)->where('subscriptionName', '!=', 'Free')->delete();
|
||||
return response()->json([
|
||||
'message' => __('Subscription plan deleted successfully'),
|
||||
'redirect' => route('admin.plans.index')
|
||||
]);
|
||||
}
|
||||
}
|
||||
38
app/Http/Controllers/Admin/AcnooPrivacyPloicyController.php
Normal file
38
app/Http/Controllers/Admin/AcnooPrivacyPloicyController.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Option;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class AcnooPrivacyPloicyController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$privacy_policy = Option::where('key', 'privacy-policy')->first();
|
||||
return view('admin.settings.privacy-policy.index', compact('privacy_policy'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'privacy_title' => 'required|string',
|
||||
'description_one' => 'required|string',
|
||||
'description_two' => 'required|string',
|
||||
]);
|
||||
|
||||
Option::updateOrCreate(
|
||||
['key' => 'privacy-policy'],
|
||||
['value' => [
|
||||
'privacy_title' => $request->privacy_title,
|
||||
'description_one' => $request->description_one,
|
||||
'description_two' => $request->description_two
|
||||
]]
|
||||
);
|
||||
|
||||
Cache::forget('privacy-policy');
|
||||
return response()->json(__('Privacy And Policy updated successfully.'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Option;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class AcnooSettingsManagerController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$otp = Option::where('key', 'email-varification')->first();
|
||||
$domain = Option::where('key', 'domain-setting')->first();
|
||||
return view('admin.manage-settings.index', compact('otp', 'domain'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'otp_status' => 'required|string|max:100|in:on,off',
|
||||
'otp_expiration_time' => 'nullable|string|max:100',
|
||||
'otp_duration_type' => 'nullable|string|max:100|in:minute,second',
|
||||
]);
|
||||
|
||||
$otpExpiration = $request->otp_status === 'on' ? $request->otp_expiration_time : null;
|
||||
$otpDurationType = $request->otp_status === 'on' ? $request->otp_duration_type : null;
|
||||
|
||||
Option::updateOrCreate(
|
||||
['key' => 'email-varification'],
|
||||
['value' => [
|
||||
'otp_status' => $request->otp_status,
|
||||
'otp_expiration_time' => $otpExpiration,
|
||||
'otp_duration_type' => $otpDurationType,
|
||||
]]
|
||||
);
|
||||
|
||||
Cache::forget('email-varification');
|
||||
|
||||
return response()->json(__('Otp setting updated successfully.'));
|
||||
}
|
||||
|
||||
public function domain(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'ssl_required' => 'required|string|max:100|in:on,off',
|
||||
'automatic_approve' => 'required|string|max:100|in:on,off',
|
||||
]);
|
||||
|
||||
Option::updateOrCreate(
|
||||
['key' => 'domain-setting'],
|
||||
['value' => [
|
||||
'ssl_required' => $request->ssl_required,
|
||||
'automatic_approve' => $request->automatic_approve,
|
||||
]]
|
||||
);
|
||||
|
||||
Cache::forget('domain-setting');
|
||||
|
||||
return response()->json(__('Domain setting updated successfully.'));
|
||||
}
|
||||
}
|
||||
144
app/Http/Controllers/Admin/AcnooSubscriptionController.php
Normal file
144
app/Http/Controllers/Admin/AcnooSubscriptionController.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\PlanSubscribe;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Modules\AffiliateAddon\App\Models\Affiliate;
|
||||
use Modules\AffiliateAddon\App\Models\AffiliateTransaction;
|
||||
|
||||
|
||||
class AcnooSubscriptionController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$search = $request->input('search');
|
||||
|
||||
$subscribers = PlanSubscribe::with(['plan:id,subscriptionName', 'business:id,companyName,business_category_id,pictureUrl', 'business.category:id,name', 'gateway:id,name'])
|
||||
->when($request->search, function ($q) use ($search) {
|
||||
$q->where(function ($q) use ($search) {
|
||||
$q->where('duration', 'like', '%' . $search . '%')
|
||||
->orWhereHas('plan', function ($q) use ($search) {
|
||||
$q->where('subscriptionName', 'like', '%' . $search . '%');
|
||||
})
|
||||
->orWhereHas('gateway', function ($q) use ($search) {
|
||||
$q->where('name', 'like', '%' . $search . '%');
|
||||
})
|
||||
->orWhereHas('business', function ($q) use ($search) {
|
||||
$q->where('companyName', 'like', '%' . $search . '%')
|
||||
->orWhereHas('category', function ($q) use ($search) {
|
||||
$q->where('name', 'like', '%' . $search . '%');
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20)
|
||||
->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('admin.subscribe-order.datas', compact('subscribers'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('admin.subscribe-order.index', compact('subscribers'));
|
||||
}
|
||||
|
||||
public function reject(Request $request, string $id)
|
||||
{
|
||||
|
||||
$request->validate([
|
||||
'notes' => 'required|string|max:255',
|
||||
]);
|
||||
|
||||
$reject = PlanSubscribe::findOrFail($id);
|
||||
|
||||
if ($reject) {
|
||||
$reject->update([
|
||||
'payment_status' => 'reject',
|
||||
'notes' => $request->notes,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Status Unpaid',
|
||||
'redirect' => route('admin.subscription-orders.index'),
|
||||
]);
|
||||
} else {
|
||||
return response()->json(['message' => 'request not found'], 404);
|
||||
}
|
||||
}
|
||||
|
||||
public function paid(Request $request, string $id)
|
||||
{
|
||||
$request->validate([
|
||||
'notes' => 'required|string|max:255',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
$subscribe = PlanSubscribe::findOrFail($id);
|
||||
|
||||
$existingNotes = $subscribe->notes ?? [];
|
||||
$updatedNotes = array_merge($existingNotes, ['reason' => $request->notes]);
|
||||
|
||||
$subscribe->update($request->except('notes') + [
|
||||
'payment_status' => 'paid',
|
||||
'notes' => $updatedNotes,
|
||||
]);
|
||||
|
||||
$subscribe->business->update([
|
||||
'subscriptionDate' => now(),
|
||||
'plan_subscribe_id' => $subscribe->id,
|
||||
'will_expire' => now()->addDays($subscribe->plan->duration),
|
||||
]);
|
||||
|
||||
$business = $subscribe->business;
|
||||
$plan = $subscribe->plan;
|
||||
if (moduleCheck('AffiliateAddon') && $business->affiliator_id) {
|
||||
$affiliateUser = User::find($business->affiliator_id);
|
||||
|
||||
if ($affiliateUser && $plan->affiliate_commission > 0) {
|
||||
$commission = ($plan->subscriptionPrice * $plan->affiliate_commission) / 100;
|
||||
|
||||
Affiliate::where('user_id', $affiliateUser->id)->increment('balance', $commission);
|
||||
|
||||
AffiliateTransaction::create([
|
||||
'user_id' => $affiliateUser->id,
|
||||
'business_id' => $business->id,
|
||||
'trx' => strtoupper(str()->random(10)),
|
||||
'type' => 'credit',
|
||||
'amount' => $commission,
|
||||
'title' => 'Commission from Order #' . $subscribe->id,
|
||||
'reference_id' => $subscribe->id,
|
||||
'reference_type' => 'PlanSubscribe',
|
||||
'note' => 'User purchased via your referral link',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
Cache::forget('plan-data-'. $subscribe->business_id);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Status Paid',
|
||||
'redirect' => route('admin.subscription-orders.index'),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json(['message' => 'request not found'], 500);
|
||||
}
|
||||
}
|
||||
|
||||
public function getInvoice($invoice_id)
|
||||
{
|
||||
$subscriber = PlanSubscribe::with(['plan:id,subscriptionName', 'business:id,companyName,business_category_id,phoneNumber,address', 'business.category:id,name', 'gateway:id,name'])->findOrFail($invoice_id);
|
||||
return view('admin.subscribe-order.invoice', compact('subscriber'));
|
||||
}
|
||||
}
|
||||
38
app/Http/Controllers/Admin/AcnooTermConditionController.php
Normal file
38
app/Http/Controllers/Admin/AcnooTermConditionController.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Option;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class AcnooTermConditionController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$term_condition = Option::where('key', 'term-condition')->first();
|
||||
return view('admin.settings.term-condition.index', compact('term_condition'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'term_title' => 'required|string',
|
||||
'description_one' => 'required|string',
|
||||
'description_two' => 'required|string',
|
||||
]);
|
||||
|
||||
Option::updateOrCreate(
|
||||
['key' => 'term-condition'],
|
||||
['value' => [
|
||||
'term_title' => $request->term_title,
|
||||
'description_one' => $request->description_one,
|
||||
'description_two' => $request->description_two
|
||||
]]
|
||||
);
|
||||
|
||||
Cache::forget('term-condition');
|
||||
return response()->json(__('Term And Condition updated successfully.'));
|
||||
}
|
||||
}
|
||||
121
app/Http/Controllers/Admin/AcnooTestimonialController.php
Normal file
121
app/Http/Controllers/Admin/AcnooTestimonialController.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Testimonial;
|
||||
use App\Helpers\HasUploader;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class AcnooTestimonialController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('permission:testimonials-read')->only('index');
|
||||
$this->middleware('permission:testimonials-create')->only('create', 'store');
|
||||
$this->middleware('permission:testimonials-update')->only('edit', 'update','status');
|
||||
$this->middleware('permission:testimonials-delete')->only('destroy','deleteAll');
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$testimonials = Testimonial::when($request->search, function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('text', 'like', '%' . $request->search . '%')
|
||||
->orWhere('client_name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('work_at', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})->latest()->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('admin.testimonials.datas', compact('testimonials'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('admin.testimonials.index', compact('testimonials'));
|
||||
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return view('admin.testimonials.create');
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'work_at' => 'nullable|string',
|
||||
'text' => 'nullable',
|
||||
'star' => 'nullable',
|
||||
'client_name' => 'required|string',
|
||||
'client_image' => 'nullable|image|mimes:jpeg,png,jpg,gif',
|
||||
]);
|
||||
|
||||
Testimonial::create($request->except('client_image') + [
|
||||
'client_image' => $request->client_image ? $this->upload($request, 'client_image') : NULL
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Testimonial created successfully'),
|
||||
'redirect' => route('admin.testimonials.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(Testimonial $testimonial)
|
||||
{
|
||||
return view('admin.testimonials.edit', compact('testimonial'));
|
||||
}
|
||||
|
||||
public function update(Request $request, Testimonial $testimonial)
|
||||
{
|
||||
$request->validate([
|
||||
'work_at' => 'nullable|string',
|
||||
'text' => 'nullable|string',
|
||||
'star' => 'nullable|integer',
|
||||
'client_name' => 'required|string',
|
||||
'client_image' => 'nullable|image|mimes:jpeg,png,jpg,gif',
|
||||
]);
|
||||
|
||||
$testimonial->update($request->except('client_image') + [
|
||||
'client_image' => $request->client_image ? $this->upload($request, 'client_image', $testimonial->client_image) : $testimonial->client_image,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Testimonial updated successfully'),
|
||||
'redirect' => route('admin.testimonials.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(Testimonial $testimonial)
|
||||
{
|
||||
if (file_exists($testimonial->client_image)) {
|
||||
Storage::delete($testimonial->client_image);
|
||||
}
|
||||
$testimonial->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Testimonial Deleted successfully'),
|
||||
'redirect' => route('admin.testimonials.index')
|
||||
]);
|
||||
}
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
$testimonials = Testimonial::whereIn('id', $request->ids)->get();
|
||||
foreach ($testimonials as $testimonial) {
|
||||
if (file_exists($testimonial->image)) {
|
||||
Storage::delete($testimonial->image);
|
||||
}
|
||||
}
|
||||
|
||||
$testimonials->each->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Selected Testimonial deleted successfully'),
|
||||
'redirect' => route('admin.testimonials.index')
|
||||
]);
|
||||
}
|
||||
}
|
||||
50
app/Http/Controllers/Admin/AcnooWebSettingController.php
Normal file
50
app/Http/Controllers/Admin/AcnooWebSettingController.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Option;
|
||||
use App\Helpers\HasUploader;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class AcnooWebSettingController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
public function index()
|
||||
{
|
||||
$page_data = get_option('manage-pages');
|
||||
return view('admin.website-setting.manage-pages', compact('page_data'));
|
||||
}
|
||||
|
||||
public function update(Request $request, $key)
|
||||
{
|
||||
$option = Option::where('key', 'manage-pages')->first();
|
||||
Option::updateOrCreate(
|
||||
['key' => 'manage-pages'],
|
||||
['value' => [
|
||||
'headings' => $request->except('_token', '_method','slider_image','scanner_image','card_icons','compatible_image','firebase_image','contact_us_icon','footer_socials_icons','footer_scanner_image','footer_apple_app_image','footer_google_app_image','watch_image','about_image','evanto_logo', 'slider_bg_img'),
|
||||
|
||||
'slider_image' => $request->slider_image ? $this->upload($request, 'slider_image') : $option->value['slider_image'] ?? null,
|
||||
'scanner_image' => $request->scanner_image ? $this->upload($request, 'scanner_image') : $option->value['scanner_image'] ?? null,
|
||||
'watch_image' => $request->watch_image ? $this->upload($request, 'watch_image') : $option->value['watch_image'] ?? null,
|
||||
'compatible_image' => $request->compatible_image ? $this->upload($request, 'compatible_image') : $option->value['compatible_image'] ?? null,
|
||||
'firebase_image' => $request->firebase_image ? $this->upload($request, 'firebase_image') : $option->value['firebase_image'] ?? null,
|
||||
'contact_us_icon' => $request->contact_us_icon ? $this->upload($request, 'contact_us_icon') : $option->value['contact_us_icon'] ?? null,
|
||||
'footer_scanner_image' => $request->footer_scanner_image ? $this->upload($request, 'footer_scanner_image') : $option->value['footer_scanner_image'] ?? null,
|
||||
'footer_apple_app_image' => $request->footer_apple_app_image ? $this->upload($request, 'footer_apple_app_image') : $option->value['footer_apple_app_image'] ?? null,
|
||||
'footer_google_app_image' => $request->footer_google_app_image ? $this->upload($request, 'footer_google_app_image') : $option->value['footer_google_app_image'] ?? null,
|
||||
'about_image' => $request->about_image ? $this->upload($request, 'about_image') : $option->value['about_image'] ?? null,
|
||||
'evanto_logo' => $request->evanto_logo ? $this->upload($request, 'evanto_logo') : $option->value['evanto_logo'] ?? null,
|
||||
'slider_bg_img' => $request->slider_bg_img ? $this->upload($request, 'slider_bg_img') : $option->value['slider_bg_img'] ?? null,
|
||||
|
||||
'card_icons' => $request->card_icons ? $this->multipleUpload($request, 'card_icons') : $option->value['card_icons'] ?? null,
|
||||
'footer_socials_icons' => $request->footer_socials_icons ? $this->multipleUpload($request, 'footer_socials_icons') : $option->value['footer_socials_icons'] ?? null,
|
||||
]
|
||||
]);
|
||||
|
||||
Cache::forget('manage-pages');
|
||||
return response()->json(__('Pages updated successfully.'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\AffiliateAddon\App\Models\AffiliateTransaction;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class AcnooWithdrawRequestController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$withdraws = AffiliateTransaction::with('user:id,name')->latest()->paginate(20);
|
||||
return view('admin.affiliate-modules.withdraws.index', compact('withdraws'));
|
||||
}
|
||||
|
||||
public function acnooFilter(Request $request)
|
||||
{
|
||||
$search = $request->input('search');
|
||||
|
||||
$withdraws = AffiliateTransaction::with('user:id,name')->when($search, function ($q) use ($search) {
|
||||
$q->where(function ($q) use ($search) {
|
||||
$q->where('amount', 'like', '%' . $search . '%')
|
||||
->orWhereHas('user', function ($q) use ($search) {
|
||||
$q->where('name', 'like', '%' . $search . '%');
|
||||
});
|
||||
});
|
||||
})
|
||||
->latest()
|
||||
->paginate($request->per_page ?? 20);
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('admin.affiliate-modules.withdraws.datas', compact('withdraws'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect(url()->previous());
|
||||
}
|
||||
|
||||
public function reject(Request $request, string $id)
|
||||
{
|
||||
$request->validate([
|
||||
'note' => 'required|string|max:255',
|
||||
]);
|
||||
|
||||
$reject = AffiliateTransaction::findOrFail($id);
|
||||
|
||||
if ($reject) {
|
||||
$reject->update([
|
||||
'status' => 'unpaid',
|
||||
'note' => $request->note,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Status Unpaid',
|
||||
'redirect' => route('admin.affiliate-withdrawals.index'),
|
||||
]);
|
||||
} else {
|
||||
return response()->json(['message' => 'request not found'], 404);
|
||||
}
|
||||
}
|
||||
|
||||
public function paid(Request $request, string $id)
|
||||
{
|
||||
$request->validate([
|
||||
'note' => 'nullable|string|max:255',
|
||||
]);
|
||||
|
||||
$paid = AffiliateTransaction::findOrFail($id);
|
||||
|
||||
if ($paid) {
|
||||
$paid->update([
|
||||
'status' => 'paid',
|
||||
'note' => $request->note,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Status Paid',
|
||||
'redirect' => route('admin.affiliate-withdrawals.index'),
|
||||
]);
|
||||
} else {
|
||||
return response()->json(['message' => 'request not found'], 404);
|
||||
}
|
||||
}
|
||||
}
|
||||
117
app/Http/Controllers/Admin/AddonController.php
Normal file
117
app/Http/Controllers/Admin/AddonController.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use ZipArchive;
|
||||
use Illuminate\Http\Request;
|
||||
use Nwidart\Modules\Facades\Module;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
|
||||
class AddonController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return view('admin.addons.index');
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'purchase_code' => 'required',
|
||||
'file' => 'required|file|mimes:zip',
|
||||
]);
|
||||
|
||||
try {
|
||||
$is_valid = true;
|
||||
$module_name = pathinfo($request->file('file')->getClientOriginalName(), PATHINFO_FILENAME);
|
||||
|
||||
if ($is_valid || $request->purchase_code == 'acnoo_license') {
|
||||
|
||||
$uploadedFile = $request->file('file');
|
||||
// Open the ZIP file using ZipArchive without saving it first
|
||||
$zip = new ZipArchive;
|
||||
$tempFilePath = $uploadedFile->getRealPath();
|
||||
|
||||
// Check if the ZIP file can be opened
|
||||
if ($zip->open($tempFilePath) === TRUE) {
|
||||
|
||||
// Define the path to the Modules folder
|
||||
$destinationPath = base_path('Modules');
|
||||
|
||||
// Ensure the Modules folder exists
|
||||
if (!File::exists($destinationPath)) {
|
||||
File::makeDirectory($destinationPath, 0755, true);
|
||||
}
|
||||
|
||||
$zip->extractTo($destinationPath);
|
||||
$zip->close();
|
||||
|
||||
// Specify the path to the module's migrations folder
|
||||
$moduleMigrationsPath = base_path('Modules/' . $module_name . '/Database/migrations');
|
||||
// Check if the migrations folder exists and contains migration files
|
||||
if (File::exists($moduleMigrationsPath)) {
|
||||
// Dynamically add the module's migrations path to the migrator
|
||||
$migrator = app('migrator');
|
||||
$migrator->path($moduleMigrationsPath);
|
||||
// Run the migrations from the module's migration path
|
||||
Artisan::call('migrate', ['--force' => true]);
|
||||
}
|
||||
|
||||
if (!moduleCheck($module_name)) {
|
||||
Artisan::call('module:seed', ['module' => $module_name]);
|
||||
}
|
||||
|
||||
// Update the modules_statuses.json file
|
||||
$filePath = base_path('modules_statuses.json');
|
||||
|
||||
// Read the contents of the JSON file
|
||||
$jsonContents = File::get($filePath);
|
||||
|
||||
// Decode the JSON into an associative array
|
||||
$data = json_decode($jsonContents, true);
|
||||
|
||||
// Add the new key-value pair to the array
|
||||
$data[$module_name] = true;
|
||||
|
||||
// Encode the array back into JSON format
|
||||
$newJsonContents = json_encode($data, JSON_PRETTY_PRINT);
|
||||
|
||||
// Write the updated contents back to the file
|
||||
File::put($filePath, $newJsonContents);
|
||||
|
||||
Artisan::call('cache:clear');
|
||||
Artisan::call('config:clear');
|
||||
Artisan::call('route:clear');
|
||||
Artisan::call('view:clear');
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Addon installed successfully.',
|
||||
'redirect' => route('admin.addons.index'),
|
||||
]);
|
||||
} else {
|
||||
return response()->json('Failed to open ZIP file', 406);
|
||||
}
|
||||
} else {
|
||||
return response()->json(['message' => __('Invalid purchase code.')], 406);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return response()->json(['success' => false, 'message' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function show($module)
|
||||
{
|
||||
$module = Module::findOrFail($module);
|
||||
if ($module->isEnabled()) {
|
||||
$module->disable();
|
||||
} else {
|
||||
$module->enable();
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Addon'
|
||||
]);
|
||||
}
|
||||
}
|
||||
54
app/Http/Controllers/Admin/DashboardController.php
Normal file
54
app/Http/Controllers/Admin/DashboardController.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Plan;
|
||||
use App\Models\User;
|
||||
use App\Models\Business;
|
||||
use App\Models\PlanSubscribe;
|
||||
use App\Models\BusinessCategory;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
|
||||
public function index()
|
||||
{
|
||||
$businesses = Business::with('enrolled_plan:id,plan_id', 'enrolled_plan.plan:id,subscriptionName', 'category:id,name')->latest()->take(5)->get();
|
||||
return view('admin.dashboard.index', compact('businesses'));
|
||||
}
|
||||
|
||||
public function getDashboardData()
|
||||
{
|
||||
$data['total_businesses'] = Business::count();
|
||||
$data['expired_businesses'] = Business::where('will_expire', '<', now())->count();
|
||||
$data['plan_subscribes'] = PlanSubscribe::count();
|
||||
$data['business_categories'] = BusinessCategory::count();
|
||||
$data['total_plans'] = Plan::count();
|
||||
$data['total_staffs'] = User::whereNotIn('role', ['superadmin', 'staff', 'shop-owner'])->count();
|
||||
|
||||
return response()->json($data);
|
||||
}
|
||||
|
||||
public function yearlySubscriptions()
|
||||
{
|
||||
$subscriptions = PlanSubscribe::whereYear('created_at', request('year') ?? date('Y'))
|
||||
->selectRaw('MONTHNAME(created_at) as month, SUM(price) as total_amount')
|
||||
->groupBy('month')
|
||||
->get();
|
||||
|
||||
return response()->json($subscriptions);
|
||||
}
|
||||
|
||||
public function plansOverview()
|
||||
{
|
||||
$subscription = PlanSubscribe::with('plan:id,subscriptionName')->select('plan_id', DB::raw('COUNT(*) as plan_count'))
|
||||
->groupBy('plan_id')
|
||||
->orderByDesc('plan_count')
|
||||
->limit(4)
|
||||
->get();
|
||||
|
||||
return response()->json($subscription);
|
||||
}
|
||||
}
|
||||
37
app/Http/Controllers/Admin/GatewayController.php
Normal file
37
app/Http/Controllers/Admin/GatewayController.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Helpers\HasUploader;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Currency;
|
||||
use App\Models\Gateway;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class GatewayController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$gateways = Gateway::all();
|
||||
$currencies = Currency::latest()->get();
|
||||
|
||||
return view('admin.gateways.index', compact('gateways', 'currencies'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
Gateway::findOrFail($id)->update($request->except('image') + [
|
||||
'image' => $request->hasFile('image') ? $this->upload($request, 'image') : NULL
|
||||
]);
|
||||
|
||||
return response()->json('Gateway updated successfully');
|
||||
}
|
||||
}
|
||||
56
app/Http/Controllers/Admin/NotificationController.php
Normal file
56
app/Http/Controllers/Admin/NotificationController.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Notification;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class NotificationController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('permission:notifications-read')->only('mtIndex');
|
||||
}
|
||||
|
||||
public function mtIndex()
|
||||
{
|
||||
$notifications = auth()->user()->notifications()
|
||||
->whereDate('created_at', today())
|
||||
->latest()
|
||||
->get();
|
||||
return view('admin.notifications.index', compact('notifications'));
|
||||
}
|
||||
|
||||
public function acnooFilter(Request $request)
|
||||
{
|
||||
$notifications = Notification::whereDate('created_at', today())->latest()->paginate($request->per_page ?? 20);
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('admin.notifications.datas', compact('notifications'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect(url()->previous());
|
||||
}
|
||||
|
||||
public function mtView($id)
|
||||
{
|
||||
$notify = Notification::find($id);
|
||||
if ($notify) {
|
||||
$notify->read_at = now();
|
||||
$notify->save();
|
||||
return redirect($notify->data['url'] ?? '/');
|
||||
}
|
||||
|
||||
return back()->with('error', __('Premission denied.'));
|
||||
}
|
||||
|
||||
public function mtReadAll()
|
||||
{
|
||||
auth()->user()->unreadNotifications()->update(['read_at' => now()]);
|
||||
return back();
|
||||
}
|
||||
|
||||
}
|
||||
40
app/Http/Controllers/Admin/PermissionController.php
Normal file
40
app/Http/Controllers/Admin/PermissionController.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
class PermissionController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('permission:permissions-read')->only('index','search');
|
||||
$this->middleware('permission:permissions-create')->only('store');
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$users = User::whereNotIn('role', ['shop-owner', 'staff', 'superadmin'])->get();
|
||||
$roles = Role::where('name', '!=', 'superadmin')->get();
|
||||
return view('admin.permissions.index', compact('roles', 'users'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'user' => ['required', 'exists:users,id'],
|
||||
'roles' => ['required', 'exists:roles,id']
|
||||
]);
|
||||
|
||||
$user = User::findOrFail($request->input('user'));
|
||||
$user->roles()->sync($request->input('roles'));
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Role permissions assigned successfully.'),
|
||||
'redirect' => route('admin.permissions.index')
|
||||
]);
|
||||
}
|
||||
}
|
||||
53
app/Http/Controllers/Admin/ProfileController.php
Normal file
53
app/Http/Controllers/Admin/ProfileController.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Helpers\HasUploader;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class ProfileController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
public function index()
|
||||
{
|
||||
$user = User::where('id',Auth::user()->id)->first();
|
||||
return view('admin.profile.index',compact('user'));
|
||||
}
|
||||
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'email' => 'required|email',
|
||||
'image' => 'nullable|image',
|
||||
]);
|
||||
$user = User::findOrFail($id);
|
||||
|
||||
if( $request->password || $request->current_password){
|
||||
if(Hash::check($request->current_password,$user->password)){
|
||||
$request->validate([
|
||||
'current_password' => 'required|string',
|
||||
'password' => 'required|string|confirmed',
|
||||
]);
|
||||
}
|
||||
else{
|
||||
return response()->json(__('Current Password does not match with old password'),404);
|
||||
}
|
||||
}
|
||||
|
||||
$user->update($request->except('image', 'password') + [
|
||||
'image' => $request->image ? $this->upload($request, 'image', $user->image) : $user->image,
|
||||
] + ($request->password ? ['password' => Hash::make($request->password)] : [])
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Profile updated successfully'),
|
||||
'redirect' => route('admin.profiles.index')
|
||||
]);
|
||||
}
|
||||
}
|
||||
104
app/Http/Controllers/Admin/RoleController.php
Normal file
104
app/Http/Controllers/Admin/RoleController.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
|
||||
class RoleController extends Controller
|
||||
{
|
||||
private $role;
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('permission:roles-create')->only('create', 'store');
|
||||
$this->middleware('permission:roles-read')->only('index', 'show');
|
||||
$this->middleware('permission:roles-update')->only('edit', 'update');
|
||||
$this->middleware('permission:roles-delete')->only('destroy');
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$roles = Role::with('users')->whereNotIn('name', ['Super Admin', 'superadmin', 'super admin'])->withCount('users')->get();
|
||||
return view('admin.roles.index', compact('roles'));
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
$groups = [];
|
||||
foreach (Permission::all() as $index => $permission) {
|
||||
$groups[ucwords(str($permission->name)->remove(['-create','-read','-update','-delete'])->replace('-', ' '))][] = $permission;
|
||||
}
|
||||
|
||||
return view('admin.roles.create', compact('groups'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => ['required', 'string', 'unique:roles,name'],
|
||||
'permissions' => ['required','array'],
|
||||
'permissions.*' => ['required', 'exists:permissions,id']
|
||||
]);
|
||||
|
||||
DB::transaction(function ()use ($request){
|
||||
$this->role = Role::create([
|
||||
'name' => $request->input('name')
|
||||
]);
|
||||
|
||||
$this->role->permissions()->sync($request->input('permissions'));
|
||||
});
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Role created successfully'),
|
||||
'redirect' => route('admin.roles.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(Role $role)
|
||||
{
|
||||
abort_if(in_array($role->name, ['Super Admin', 'superadmin', 'super admin']), 403, __("You are not allowed to mess with Super Admin"));
|
||||
$role->load('permissions');
|
||||
$groups = [];
|
||||
foreach (Permission::all() as $index => $permission) {
|
||||
$groups[ucwords(str($permission->name)->remove(['-', 'create','read','update','delete','status','list','folder']))][] = $permission;
|
||||
}
|
||||
|
||||
return view('admin.roles.edit', compact('role', 'groups'));
|
||||
}
|
||||
|
||||
public function update(Request $request, Role $role)
|
||||
{
|
||||
abort_if(in_array($role->name, ['Super Admin', 'superadmin', 'super admin']), 403, __("You are not allowed to mess with Super Admin"));
|
||||
$request->validate([
|
||||
'name' => ['required', 'string', Rule::unique('roles')->ignore($role->id)],
|
||||
'permissions' => ['required','array'],
|
||||
'permissions.*' => ['required', 'exists:permissions,id']
|
||||
]);
|
||||
|
||||
$role->update([
|
||||
'name' => $request->input('name')
|
||||
]);
|
||||
|
||||
$role->permissions()->sync($request->input('permissions'));
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Role update successfully'),
|
||||
'redirect' => route('admin.roles.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(Role $role)
|
||||
{
|
||||
abort_if(in_array($role->name, ['Super Admin', 'superadmin', 'super admin']), 403, __("You are not allowed to mess with Super Admin"));
|
||||
$role->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Role deleted successfully'),
|
||||
'redirect' => route('admin.roles.index')
|
||||
]);
|
||||
}
|
||||
}
|
||||
63
app/Http/Controllers/Admin/SettingController.php
Normal file
63
app/Http/Controllers/Admin/SettingController.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Helpers\HasUploader;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Option;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class SettingController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('permission:settings-read')->only('index');
|
||||
$this->middleware('permission:settings-update')->only('update');
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$general = Option::where('key', 'general')->first();
|
||||
$languages = json_decode(file_get_contents(base_path('lang/langlist.json')), true);
|
||||
|
||||
return view('admin.settings.general', compact('general', 'languages'));
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$request->validate([
|
||||
'title' => 'required|string|max:100',
|
||||
'logo' => 'nullable|image',
|
||||
'favicon' => 'nullable|image',
|
||||
'common_header_logo' => 'nullable|image',
|
||||
'footer_logo' => 'nullable|image',
|
||||
'admin_logo' => 'nullable|image',
|
||||
'login_page_logo' => 'nullable|image',
|
||||
'login_page_image' => 'nullable|image',
|
||||
'app_link' => 'nullable|url',
|
||||
'whatsapp_number' => 'nullable|string|max:20',
|
||||
]);
|
||||
|
||||
$general = Option::findOrFail($id);
|
||||
Cache::forget($general->key);
|
||||
$general->update([
|
||||
'value' => $request->except('_token', '_method', 'logo', 'favicon', 'common_header_logo', 'footer_logo', 'admin_logo', 'login_page_logo', 'login_page_image') + [
|
||||
'logo' => $request->logo ? $this->upload($request, 'logo', $general->value['logo'] ?? null) : ($general->value['logo'] ?? null),
|
||||
'favicon' => $request->favicon ? $this->upload($request, 'favicon', $general->value['favicon'] ?? null) : ($general->value['favicon'] ?? null),
|
||||
'common_header_logo' => $request->common_header_logo ? $this->upload($request, 'common_header_logo', $general->value['common_header_logo'] ?? null) : ($general->value['common_header_logo'] ?? null),
|
||||
'footer_logo' => $request->footer_logo ? $this->upload($request, 'footer_logo', $general->value['footer_logo'] ?? null) : ($general->value['footer_logo'] ?? null),
|
||||
'admin_logo' => $request->admin_logo ? $this->upload($request, 'admin_logo', $general->value['admin_logo'] ?? null) : ($general->value['admin_logo'] ?? null),
|
||||
'login_page_logo' => $request->login_page_logo ? $this->upload($request, 'login_page_logo', $general->value['login_page_logo'] ?? null) : ($general->value['login_page_logo'] ?? null),
|
||||
'login_page_image' => $request->login_page_image ? $this->upload($request, 'login_page_image', $general->value['login_page_image'] ?? null) : ($general->value['login_page_image'] ?? null),
|
||||
]
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('General Setting updated successfully'),
|
||||
'redirect' => route('admin.settings.index')
|
||||
]);
|
||||
}
|
||||
}
|
||||
85
app/Http/Controllers/Admin/SubscriptionReport.php
Normal file
85
app/Http/Controllers/Admin/SubscriptionReport.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\PlanSubscribe;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class SubscriptionReport extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$subscribeQuery = PlanSubscribe::with(['plan:id,subscriptionName', 'business:id,companyName,business_category_id,pictureUrl', 'business.category:id,name', 'gateway:id,name'])->whereDate('created_at', Carbon::today()->format('Y-m-d'));
|
||||
|
||||
// Date filter
|
||||
$startDate = Carbon::today()->format('Y-m-d');
|
||||
$endDate = Carbon::today()->format('Y-m-d');
|
||||
|
||||
switch ($request->custom_days) {
|
||||
case 'yesterday':
|
||||
$startDate = $endDate = Carbon::yesterday()->format('Y-m-d');
|
||||
break;
|
||||
case 'last_seven_days':
|
||||
$startDate = Carbon::today()->subDays(6)->format('Y-m-d');
|
||||
break;
|
||||
case 'last_thirty_days':
|
||||
$startDate = Carbon::today()->subDays(29)->format('Y-m-d');
|
||||
break;
|
||||
case 'current_month':
|
||||
$startDate = Carbon::now()->startOfMonth()->format('Y-m-d');
|
||||
$endDate = Carbon::now()->endOfMonth()->format('Y-m-d');
|
||||
break;
|
||||
case 'last_month':
|
||||
$startDate = Carbon::now()->subMonth()->startOfMonth()->format('Y-m-d');
|
||||
$endDate = Carbon::now()->subMonth()->endOfMonth()->format('Y-m-d');
|
||||
break;
|
||||
case 'current_year':
|
||||
$startDate = Carbon::now()->startOfYear()->format('Y-m-d');
|
||||
$endDate = Carbon::now()->endOfYear()->format('Y-m-d');
|
||||
break;
|
||||
case 'custom_date':
|
||||
if ($request->from_date && $request->to_date) {
|
||||
$startDate = Carbon::parse($request->from_date)->format('Y-m-d');
|
||||
$endDate = Carbon::parse($request->to_date)->format('Y-m-d');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$subscribeQuery->whereDate('created_at', '>=', $startDate)
|
||||
->whereDate('created_at', '<=', $endDate);
|
||||
|
||||
// Search filter
|
||||
if ($request->filled('search')) {
|
||||
$search = $request->search;
|
||||
$subscribeQuery->where(function ($query) use ($search) {
|
||||
$query->where('duration', 'like', '%' . $search . '%')
|
||||
->orWhereHas('plan', function ($q) use ($search) {
|
||||
$q->where('subscriptionName', 'like', '%' . $search . '%');
|
||||
})
|
||||
->orWhereHas('gateway', function ($q) use ($search) {
|
||||
$q->where('name', 'like', '%' . $search . '%');
|
||||
})
|
||||
->orWhereHas('business', function ($q) use ($search) {
|
||||
$q->where('companyName', 'like', '%' . $search . '%')
|
||||
->orWhereHas('category', function ($q) use ($search) {
|
||||
$q->where('name', 'like', '%' . $search . '%');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$perPage = $request->input('per_page', 20);
|
||||
$subscribers = $subscribeQuery->latest()->paginate($perPage)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('admin.subscribers.datas', compact('subscribers'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('admin.subscribers.index', compact('subscribers'));
|
||||
}
|
||||
|
||||
}
|
||||
165
app/Http/Controllers/Admin/SystemSettingController.php
Normal file
165
app/Http/Controllers/Admin/SystemSettingController.php
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
|
||||
class SystemSettingController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('permission:settings-read')->only('index');
|
||||
$this->middleware('permission:settings-update')->only('update');
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
return view('admin.settings.system');
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'SESSION_LIFETIME' => 'required|integer',
|
||||
'service_account_credentials' => 'mimes:json,txt|max:100',
|
||||
]);
|
||||
|
||||
if ($request->hasFile('service_account_credentials')) {
|
||||
$file = $request->file('service_account_credentials');
|
||||
$name = 'service-account-credentials.json';
|
||||
$path = 'uploads/';
|
||||
$file->move($path, $name);
|
||||
}
|
||||
|
||||
$APP_NAME = '"' . $request->APP_NAME . '"';
|
||||
|
||||
$txt = "APP_NAME=" . $APP_NAME . "
|
||||
APP_ENV=local
|
||||
APP_KEY=" . env('APP_KEY') . "
|
||||
APP_DEBUG=" . $request->APP_DEBUG . "
|
||||
APP_URL=" . url('/') . "
|
||||
SITE_KEY=" . env('SITE_KEY') . "
|
||||
AUTHORIZED_KEY=" . env('AUTHORIZED_KEY') . "
|
||||
|
||||
CONTENT_EDITOR=" . $request->CONTENT_EDITOR . "
|
||||
ANALYTICS_VIEW_ID=" . $request->ANALYTICS_VIEW_ID . "
|
||||
GA_MEASUREMENT_ID=" . $request->GA_MEASUREMENT_ID . "
|
||||
FORCE_USER_TO_PURCHASE_PLAN=" . $request->FORCE_USER_TO_PURCHASE_PLAN . "
|
||||
UNSUBSCRIBE_AFTER_DAYS=" . $request->UNSUBSCRIBE_AFTER_DAYS . "
|
||||
|
||||
|
||||
DB_CONNECTION=" . env("DB_CONNECTION") . "
|
||||
DB_HOST=" . env("DB_HOST") . "
|
||||
DB_PORT=" . env("DB_PORT") . "
|
||||
DB_DATABASE=" . env("DB_DATABASE") . "
|
||||
DB_USERNAME=" . env("DB_USERNAME") . "
|
||||
DB_PASSWORD=" . env("DB_PASSWORD") . "
|
||||
|
||||
|
||||
QUEUE_MAIL=" . $request->QUEUE_MAIL . "
|
||||
" . $request->MAIL_DRIVER_TYPE . "=" . $request->MAIL_DRIVER . "
|
||||
MAIL_DRIVER_TYPE=" . $request->MAIL_DRIVER_TYPE . "
|
||||
MAIL_HOST=" . $request->MAIL_HOST . "
|
||||
MAIL_PORT=" . $request->MAIL_PORT . "
|
||||
MAIL_USERNAME=" . $request->MAIL_USERNAME . "
|
||||
MAIL_PASSWORD=" . $request->MAIL_PASSWORD . "
|
||||
MAIL_ENCRYPTION=" . $request->MAIL_ENCRYPTION . "
|
||||
MAIL_FROM_ADDRESS=" . $request->MAIL_FROM_ADDRESS . "
|
||||
MAIL_TO=" . $request->MAIL_TO . "
|
||||
MAIL_FROM_NAME='" . $request->MAIL_FROM_NAME . "'
|
||||
|
||||
|
||||
MAILCHIMP_DRIVER=" . $request->MAILCHIMP_DRIVER . "
|
||||
MAILCHIMP_APIKEY=" . $request->MAILCHIMP_APIKEY . "
|
||||
MAILCHIMP_LIST_ID=" . $request->MAILCHIMP_LIST_ID . "
|
||||
|
||||
NOCAPTCHA_SECRET=" . $request->NOCAPTCHA_SECRET . "
|
||||
NOCAPTCHA_SITEKEY=" . $request->NOCAPTCHA_SITEKEY . "
|
||||
|
||||
BROADCAST_DRIVER=pusher
|
||||
CACHE_DRIVER=" . $request->CACHE_DRIVER . "
|
||||
QUEUE_CONNECTION=database
|
||||
SESSION_DRIVER=" . $request->SESSION_DRIVER . "
|
||||
SESSION_LIFETIME=" . $request->SESSION_LIFETIME . "
|
||||
|
||||
PUSHER_APP_ID=" . $request->PUSHER_APP_ID . "
|
||||
PUSHER_APP_KEY=" . $request->PUSHER_APP_KEY . "
|
||||
PUSHER_APP_SECRET=" . $request->PUSHER_APP_SECRET . "
|
||||
PUSHER_APP_CLUSTER=" . $request->PUSHER_APP_CLUSTER . "
|
||||
PUSHER_SCHEME=https
|
||||
MIX_PUSHER_APP_KEY=" . '${PUSHER_APP_KEY}' . "
|
||||
MIX_PUSHER_APP_CLUSTER=" . '${PUSHER_APP_CLUSTER}' . "
|
||||
|
||||
REDIS_HOST=" . $request->REDIS_HOST . "
|
||||
REDIS_PORT=" . $request->REDIS_PORT . "
|
||||
REDIS_URL=" . $request->REDIS_URL . "
|
||||
REDIS_PASSWORD=" . $request->REDIS_PASSWORD . "
|
||||
|
||||
MEMCACHED_HOST=" . $request->MEMCACHED_HOST . "
|
||||
MEMCACHED_PORT=" . $request->MEMCACHED_PORT . "
|
||||
MEMCACHED_PERSISTENT_ID=" . $request->MEMCACHED_PERSISTENT_ID . "
|
||||
MEMCACHED_USERNAME=" . $request->MEMCACHED_USERNAME . "
|
||||
MEMCACHED_PASSWORD=" . $request->MEMCACHED_PASSWORD . "
|
||||
|
||||
|
||||
AWS_ACCESS_KEY_ID=" . $request->AWS_ACCESS_KEY_ID . "
|
||||
AWS_SECRET_ACCESS_KEY=" . $request->AWS_SECRET_ACCESS_KEY . "
|
||||
AWS_DEFAULT_REGION=" . $request->AWS_DEFAULT_REGION . "
|
||||
AWS_BUCKET=" . $request->AWS_BUCKET . "
|
||||
|
||||
WAS_ACCESS_KEY_ID=" . $request->WAS_ACCESS_KEY_ID . "
|
||||
WAS_SECRET_ACCESS_KEY=" . $request->WAS_SECRET_ACCESS_KEY . "
|
||||
WAS_DEFAULT_REGION=" . $request->WAS_DEFAULT_REGION . "
|
||||
WAS_BUCKET=" . $request->WAS_BUCKET . "
|
||||
WAS_ENDPOINT=" . $request->WAS_ENDPOINT . "
|
||||
|
||||
|
||||
DISCUSS_COMMENT_KEY=" . $request->DISCUSS_COMMENT_KEY . "
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_LEVEL=debug
|
||||
CACHE_LIFETIME=" . $request->CACHE_LIFETIME . "
|
||||
TIMEZONE=" . $request->TIMEZONE . "
|
||||
|
||||
DEFAULT_LANG=" . $request->DEFAULT_LANG . "
|
||||
DISCUSS_COMMENT_KEY=" . $request->DISCUSS_COMMENT_KEY . "
|
||||
|
||||
FILESYSTEM_DISK=" . $request->FILESYSTEM_DISK . "
|
||||
|
||||
VITE_PUSHER_APP_KEY=" . '${PUSHER_APP_KEY}' . "
|
||||
VITE_PUSHER_HOST=" . '${PUSHER_HOST}' . "
|
||||
VITE_PUSHER_PORT=" . '${PUSHER_PORT}' . "
|
||||
VITE_PUSHER_SCHEME=" . '${PUSHER_SCHEME}' . "
|
||||
VITE_PUSHER_APP_CLUSTER=" . '${PUSHER_APP_CLUSTER}' . "
|
||||
|
||||
APILAYER_API_KEY=" . $request->APILAYER_API_KEY . "
|
||||
|
||||
GOOGLE_CLIENT_ID=" . $request->GOOGLE_CLIENT_ID . "
|
||||
GOOGLE_CLIENT_SECRET=" . $request->GOOGLE_CLIENT_SECRET . "
|
||||
GOOGLE_REDIRECT_URI=" . url('login/google/callback') . "
|
||||
|
||||
TWITTER_CLIENT_ID=" . $request->TWITTER_CLIENT_ID . "
|
||||
TWITTER_CLIENT_SECRET=" . $request->TWITTER_CLIENT_SECRET . "
|
||||
TWITTER_REDIRECT_URI=" . url('login/twitter/callback') . "
|
||||
|
||||
WKHTMLTOPDF_BINARY=" . $request->WKHTMLTOPDF_BINARY . "
|
||||
WKHTMLTOIMAGE_BINARY=" . $request->WKHTMLTOIMAGE_BINARY . "
|
||||
WKHTMLTOPDF_TIMEOUT=" . $request->WKHTMLTOPDF_TIMEOUT . "
|
||||
|
||||
";
|
||||
|
||||
File::put(base_path('.env'), $txt);
|
||||
|
||||
Artisan::call('config:clear');
|
||||
Artisan::call('cache:clear');
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Settings updated successfully.'),
|
||||
'redirect' => route('admin.system-settings.index'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
139
app/Http/Controllers/Admin/UserController.php
Normal file
139
app/Http/Controllers/Admin/UserController.php
Normal file
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Helpers\HasUploader;
|
||||
use Illuminate\Http\Request;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('permission:users-create')->only('create', 'store');
|
||||
$this->middleware('permission:users-read')->only('index', 'show');
|
||||
$this->middleware('permission:users-update')->only('edit', 'update');
|
||||
$this->middleware('permission:users-delete')->only('destroy');
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$users = User::whereNotIn('role', ['superadmin', 'staff', 'shop-owner'])->when($request->search, function ($q) use ($request) {
|
||||
$q->where(function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%')
|
||||
->orWhere('email', 'like', '%' . $request->search . '%')
|
||||
->orWhere('role', 'like', '%' . $request->search . '%')
|
||||
->orWhere('phone', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
})->latest()->paginate($request->per_page ?? 20)->appends($request->query());
|
||||
|
||||
if ($request->ajax()) {
|
||||
return response()->json([
|
||||
'data' => view('admin.users.datas', compact('users'))->render()
|
||||
]);
|
||||
}
|
||||
|
||||
return view('admin.users.index', compact('users'));
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
$roles = Role::where('name', '!=', 'superadmin')->latest()->get();
|
||||
return view('admin.users.create', compact('roles'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'role' => 'required|string',
|
||||
'phone' => 'nullable|string',
|
||||
'email' => 'required|email|unique:users',
|
||||
'password' => 'required|string|confirmed',
|
||||
'image' => 'nullable|image',
|
||||
]);
|
||||
|
||||
$user = User::create($request->except('image', 'password') + [
|
||||
'image' => $request->image ? $this->upload($request, 'image') : null,
|
||||
'password' => Hash::make($request->password),
|
||||
]);
|
||||
|
||||
$role = Role::where('name', $request->role)->first();
|
||||
$user->roles()->sync($role->id);
|
||||
|
||||
sendNotification($user->id, route('admin.users.index', ['users' => $request->role]), __(ucfirst($request->role) . ' has been created.'), 'action', null, null, true);
|
||||
return response()->json([
|
||||
'message' => __(ucfirst($request->role) . ' created successfully'),
|
||||
'redirect' => route('admin.users.index', ['users' => $request->role])
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(User $user)
|
||||
{
|
||||
if ($user->role == 'superadmin') {
|
||||
abort(403);
|
||||
}
|
||||
$roles = Role::latest()->get();
|
||||
return view('admin.users.edit', compact('user', 'roles'));
|
||||
}
|
||||
|
||||
public function update(Request $request, User $user)
|
||||
{
|
||||
if ($user->role == 'superadmin') {
|
||||
return response()->json(__('You can not update a superadmin.'), 400);
|
||||
}
|
||||
$request->validate([
|
||||
'role' => 'required|string',
|
||||
'phone' => 'nullable|string',
|
||||
'country' => 'nullable|string',
|
||||
'name' => 'required|string|max:255',
|
||||
'email' => 'required|email|unique:users,email,' . $user->id,
|
||||
'password' => 'nullable|string|confirmed',
|
||||
'image' => 'nullable|image',
|
||||
]);
|
||||
|
||||
$role = Role::where('name', $request->role)->first();
|
||||
$user->roles()->sync($role->id);
|
||||
$user->update($request->except('image', 'password') + [
|
||||
'image' => $request->image ? $this->upload($request, 'image', $user->image) : $user->image,
|
||||
'password' => $request->password ? Hash::make($request->password) : $user->password,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Staff updated successfully'),
|
||||
'redirect' => route('admin.users.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(User $user)
|
||||
{
|
||||
if ($user->role == 'superadmin') {
|
||||
return response()->json(__('You can not delete a superadmin.'), 400);
|
||||
}
|
||||
|
||||
if (file_exists($user->image)) {
|
||||
Storage::delete($user->image);
|
||||
}
|
||||
|
||||
$user->delete();
|
||||
return response()->json([
|
||||
'message' => __('Staff deleted successfully'),
|
||||
'redirect' => route('admin.users.index')
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteAll(Request $request)
|
||||
{
|
||||
User::whereIn('id', $request->ids)->delete();
|
||||
return response()->json([
|
||||
'message' => __('Selected Staff deleted successfully'),
|
||||
'redirect' => route('admin.users.index')
|
||||
]);
|
||||
}
|
||||
}
|
||||
19
app/Http/Controllers/Api/AcnooBannerController.php
Normal file
19
app/Http/Controllers/Api/AcnooBannerController.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Banner;
|
||||
|
||||
class AcnooBannerController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$banners = Banner::where('status', 1)->latest()->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $banners,
|
||||
]);
|
||||
}
|
||||
}
|
||||
73
app/Http/Controllers/Api/AcnooBrandController.php
Normal file
73
app/Http/Controllers/Api/AcnooBrandController.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Brand;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AcnooBrandController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$data = Brand::where('business_id', auth()->user()->business_id)->latest()->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'brandName' => 'required|unique:brands,brandName,NULL,id,business_id,' . auth()->user()->business_id,
|
||||
]);
|
||||
|
||||
$data = Brand::create($request->all() + [
|
||||
'business_id' => auth()->user()->business_id
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, Brand $brand)
|
||||
{
|
||||
$request->validate([
|
||||
'brandName' => [
|
||||
'required',
|
||||
'unique:brands,brandName,' . $brand->id . ',id,business_id,' . auth()->user()->business_id,
|
||||
],
|
||||
]);
|
||||
|
||||
$brand = $brand->update($request->all());
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $brand,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(Brand $brand)
|
||||
{
|
||||
$brand->delete();
|
||||
return response()->json([
|
||||
'message' => __('Data deleted successfully.'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
87
app/Http/Controllers/Api/AcnooCategoryController.php
Normal file
87
app/Http/Controllers/Api/AcnooCategoryController.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Category;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AcnooCategoryController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$data = Category::where('business_id', auth()->user()->business_id)->latest()->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
$request->validate([
|
||||
'categoryName' => 'required|unique:categories,categoryName,NULL,id,business_id,' . $business_id,
|
||||
]);
|
||||
|
||||
$data = Category::create([
|
||||
'categoryName' => $request->categoryName,
|
||||
'variationCapacity' => $request->variationCapacity == 'true' ? 1 : 0,
|
||||
'variationColor' => $request->variationColor == 'true' ? 1 : 0,
|
||||
'variationSize' => $request->variationSize == 'true' ? 1 : 0,
|
||||
'variationType' => $request->variationType == 'true' ? 1 : 0,
|
||||
'variationWeight' => $request->variationWeight == 'true' ? 1 : 0,
|
||||
'business_id' => $business_id
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, Category $category)
|
||||
{
|
||||
$request->validate([
|
||||
'categoryName' => [
|
||||
'required',
|
||||
'unique:categories,categoryName,' . $category->id . ',id,business_id,' . auth()->user()->business_id,
|
||||
],
|
||||
]);
|
||||
|
||||
$category = $category->update([
|
||||
'categoryName' => $request->categoryName,
|
||||
'variationCapacity' => $request->variationCapacity == 'true' ? 1 : 0,
|
||||
'variationColor' => $request->variationColor == 'true' ? 1 : 0,
|
||||
'variationSize' => $request->variationSize == 'true' ? 1 : 0,
|
||||
'variationType' => $request->variationType == 'true' ? 1 : 0,
|
||||
'variationWeight' => $request->variationWeight == 'true' ? 1 : 0,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $category,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(Category $category)
|
||||
{
|
||||
$category->delete();
|
||||
return response()->json([
|
||||
'message' => __('Data deleted successfully.'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
45
app/Http/Controllers/Api/AcnooCurrencyController.php
Normal file
45
app/Http/Controllers/Api/AcnooCurrencyController.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Currency;
|
||||
use App\Models\UserCurrency;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AcnooCurrencyController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$currencies = Currency::orderBy('is_default', 'desc')->orderBy('status', 'desc')->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $currencies
|
||||
]);
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
{
|
||||
$currency = Currency::findOrFail($id);
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$user_currency = UserCurrency::where('business_id', $business_id)->first();
|
||||
|
||||
$user_currency->update([
|
||||
'name' => $currency->name,
|
||||
'code' => $currency->code,
|
||||
'rate' => $currency->rate,
|
||||
'symbol' => $currency->symbol,
|
||||
'position' => $currency->position,
|
||||
'country_name' => $currency->country_name,
|
||||
]);
|
||||
|
||||
cache()->forget("business_currency_" . $business_id);
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message', __('Currency changed successfully'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
249
app/Http/Controllers/Api/AcnooDueController.php
Normal file
249
app/Http/Controllers/Api/AcnooDueController.php
Normal file
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Events\DuePaymentReceived;
|
||||
use App\Events\MultiPaymentProcessed;
|
||||
use App\Models\Sale;
|
||||
use App\Models\Party;
|
||||
use App\Models\Business;
|
||||
use App\Models\Purchase;
|
||||
use App\Models\DueCollect;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class AcnooDueController extends Controller
|
||||
{
|
||||
Use DateFilterTrait;
|
||||
|
||||
public function index()
|
||||
{
|
||||
$query = DueCollect::with('user:id,name,role', 'party:id,name,email,phone,type,address', 'branch:id,name,phone,address','transactions:id,platform,transaction_type,amount,date,invoice_no,reference_id,payment_type_id,meta', 'transactions.paymentType:id,name')
|
||||
->where('business_id', auth()->user()->business_id);
|
||||
|
||||
// Apply date filter
|
||||
if(request('duration')){
|
||||
$this->applyDateFilter($query, request('duration'), 'paymentDate', request('from_date'), request('to_date'));
|
||||
}
|
||||
|
||||
$data = $query->latest()->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$party = Party::find($request->party_id);
|
||||
|
||||
$request->validate([
|
||||
'paymentDate' => 'required|string',
|
||||
'payDueAmount' => 'nullable|numeric',
|
||||
'party_id' => 'required|exists:parties,id',
|
||||
'invoiceNumber' => 'nullable|exists:' . ($party->type == 'Supplier' ? 'purchases' : 'sales') . ',invoiceNumber',
|
||||
]);
|
||||
|
||||
$user = auth()->user();
|
||||
$action_branch_id = $user->branch_id ?? $user->active_branch_id;
|
||||
$payments = $request->payments ?? [];
|
||||
|
||||
$payDueAmount = collect($payments)
|
||||
->reject(fn($p) => strtolower($p['type'] ?? '') === 'cheque')
|
||||
->sum(fn($p) => $p['amount'] ?? 0);
|
||||
|
||||
if ($action_branch_id != $party->branch_id && !$request->invoiceNumber) {
|
||||
return response()->json([
|
||||
'message' => __('You must select an invoice when login any branch.')
|
||||
], 400);
|
||||
}
|
||||
|
||||
$branch_id = null;
|
||||
if ($request->invoiceNumber) {
|
||||
if ($party->type == 'Supplier') {
|
||||
$invoice = Purchase::where('invoiceNumber', $request->invoiceNumber)->where('party_id', $request->party_id)->first();
|
||||
} else {
|
||||
$invoice = Sale::where('invoiceNumber', $request->invoiceNumber)->where('party_id', $request->party_id)->first();
|
||||
}
|
||||
|
||||
if (!isset($invoice)) {
|
||||
return response()->json([
|
||||
'message' => 'Invoice Not Found.'
|
||||
], 404);
|
||||
}
|
||||
|
||||
if (!auth()->user()->active_branch) {
|
||||
if (isset($invoice) && isset($invoice->branch_id)) {
|
||||
$branch_id = $invoice->branch_id;
|
||||
}
|
||||
}
|
||||
|
||||
if ($invoice->dueAmount < $request->payDueAmount) {
|
||||
return response()->json([
|
||||
'message' => 'Invoice due is ' . $invoice->dueAmount . '. You can not pay more then the invoice due amount.'
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$request->invoiceNumber) {
|
||||
if ($party->type == 'Supplier') {
|
||||
$all_invoice_due = Purchase::where('party_id', $request->party_id)->sum('dueAmount');
|
||||
} else {
|
||||
$all_invoice_due = Sale::where('party_id', $request->party_id)->sum('dueAmount');
|
||||
}
|
||||
|
||||
if (($all_invoice_due + $request->payDueAmount) > $party->due) {
|
||||
return response()->json([
|
||||
'message' => __('You can pay only '. $party->due - $all_invoice_due .', without selecting an invoice.')
|
||||
], 400);
|
||||
}
|
||||
|
||||
if ($party->opening_balance_type == 'due') {
|
||||
$party->update([
|
||||
'opening_balance' => max(0, $party->opening_balance - $payDueAmount),
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$data = DueCollect::create($request->all() + [
|
||||
'user_id' => auth()->id(),
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'sale_id' => $party->type != 'Supplier' && isset($invoice) ? $invoice->id : NULL,
|
||||
'purchase_id' => $party->type == 'Supplier' && isset($invoice) ? $invoice->id : NULL,
|
||||
'totalDue' => isset($invoice) ? $invoice->dueAmount : $party->due,
|
||||
'dueAmountAfterPay' => isset($invoice) ? ($invoice->dueAmount - $payDueAmount) : ($party->due - $payDueAmount),
|
||||
]);
|
||||
|
||||
if (isset($invoice)) {
|
||||
$invoice->update([
|
||||
'dueAmount' => $invoice->dueAmount - $payDueAmount
|
||||
]);
|
||||
}
|
||||
|
||||
$party->type == 'Supplier' ? updateBalance($payDueAmount, 'decrement', $branch_id) : updateBalance($payDueAmount, 'increment', $branch_id);
|
||||
|
||||
$party->update([
|
||||
'due' => $party->due - $payDueAmount
|
||||
]);
|
||||
|
||||
// MultiPaymentProcessed Event
|
||||
event(new MultiPaymentProcessed(
|
||||
$payments,
|
||||
$data->id,
|
||||
'due_collect',
|
||||
$payDueAmount,
|
||||
$party->id
|
||||
));
|
||||
|
||||
// Send SMS
|
||||
event(new DuePaymentReceived($data));
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data->load('user:id,name,role', 'party:id,name,email,phone,type,address', 'branch:id,name,phone,address','transactions:id,platform,transaction_type,amount,date,invoice_no,reference_id,payment_type_id,meta', 'transactions.paymentType:id,name'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function invoiceWiseDue()
|
||||
{
|
||||
$data = Sale::select('id','dueAmount', 'paidAmount', 'totalAmount', 'invoiceNumber', 'saleDate', 'meta')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereNull('party_id')
|
||||
->where('dueAmount', '>', 0)
|
||||
->latest()->paginate(10);
|
||||
|
||||
// Sum only for paginate data
|
||||
$total_receivable = $data->getCollection()->sum('dueAmount');
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'total_receivable' => (float) $total_receivable,
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function collectInvoiceDue(Request $request)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$request->validate([
|
||||
'paymentDate' => 'required|string',
|
||||
'payDueAmount' => 'nullable|numeric',
|
||||
'invoiceNumber' => 'required|string|exists:sales,invoiceNumber',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$invoice = Sale::where('business_id', $business_id)->where('invoiceNumber', $request->invoiceNumber)->whereNull('party_id')->first();
|
||||
|
||||
if (!$invoice) {
|
||||
return response()->json([
|
||||
'message' => 'Invoice Not Found.'
|
||||
], 404);
|
||||
}
|
||||
$payments = $request->payments ?? [];
|
||||
|
||||
$payDueAmount = collect($payments)
|
||||
->reject(fn($p) => strtolower($p['type'] ?? '') === 'cheque')
|
||||
->sum(fn($p) => $p['amount'] ?? 0);
|
||||
|
||||
|
||||
if ($invoice->dueAmount < $payDueAmount) {
|
||||
return response()->json([
|
||||
'message' => 'Invoice due is ' . $invoice->dueAmount . '. You cannot pay more than the invoice due amount.'
|
||||
], 400);
|
||||
}
|
||||
|
||||
$data = DueCollect::create([
|
||||
'user_id' => auth()->id(),
|
||||
'business_id' => $business_id,
|
||||
'sale_id' => $invoice->id,
|
||||
'invoiceNumber' => $request->invoiceNumber,
|
||||
'totalDue' => $invoice->dueAmount,
|
||||
'dueAmountAfterPay' => $invoice->dueAmount - $payDueAmount,
|
||||
'payDueAmount' => $payDueAmount,
|
||||
'payment_type_id' => $request->payment_type_id,
|
||||
'paymentDate' => $request->paymentDate,
|
||||
]);
|
||||
|
||||
$invoice->update([
|
||||
'dueAmount' => $invoice->dueAmount - $payDueAmount
|
||||
]);
|
||||
|
||||
$business = Business::findOrFail($business_id);
|
||||
$business->update([
|
||||
'remainingShopBalance' => $business->remainingShopBalance + $payDueAmount
|
||||
]);
|
||||
|
||||
sendNotifyToUser($data->id, route('business.dues.index', ['id' => $data->id]), __('Due Collection has been created.'), $business_id);
|
||||
|
||||
// MultiPaymentProcessed Event
|
||||
event(new MultiPaymentProcessed(
|
||||
$payments,
|
||||
$data->id,
|
||||
'due_collect',
|
||||
$payDueAmount,
|
||||
));
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data->load('user:id,name', 'party:id,name,email,phone,type,address','transactions:id,platform,transaction_type,amount,date,invoice_no,reference_id,payment_type_id,meta', 'transactions.paymentType:id,name'),
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
'message' => 'Something went wrong!',
|
||||
'error' => $e->getMessage(),
|
||||
], 500);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
105
app/Http/Controllers/Api/AcnooExpenseController.php
Normal file
105
app/Http/Controllers/Api/AcnooExpenseController.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use App\Models\Expense;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Events\MultiPaymentProcessed;
|
||||
use App\Traits\DateFilterTrait;
|
||||
|
||||
class AcnooExpenseController extends Controller
|
||||
{
|
||||
use DateFilterTrait;
|
||||
public function index(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
$expenseQuery = Expense::with(['category:id,categoryName', 'payment_type:id,name', 'branch:id,name'])->where('business_id', $businessId);
|
||||
|
||||
$expenseQuery->when($request->branch_id, function ($q) use ($request) {
|
||||
$q->where('branch_id', $request->branch_id);
|
||||
});
|
||||
|
||||
// Apply date filter
|
||||
if(request('duration')){
|
||||
$this->applyDateFilter($expenseQuery, request('duration'), 'expenseDate', request('from_date'), request('to_date'));
|
||||
}
|
||||
|
||||
// Search Filter
|
||||
if ($request->filled('search')) {
|
||||
$expenseQuery->where(function ($query) use ($request) {
|
||||
$query->where('expanseFor', 'like', '%' . $request->search . '%')
|
||||
->orWhere('paymentType', 'like', '%' . $request->search . '%')
|
||||
->orWhere('referenceNo', 'like', '%' . $request->search . '%')
|
||||
->orWhere('amount', 'like', '%' . $request->search . '%')
|
||||
->orWhereHas('category', function ($q) use ($request) {
|
||||
$q->where('categoryName', 'like', '%' . $request->search . '%');
|
||||
})
|
||||
->orWhereHas('payment_type', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
})
|
||||
->orWhereHas('branch', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$data = $expenseQuery->latest()->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'expense_category_id' => 'required|exists:expense_categories,id',
|
||||
'expanseFor' => 'nullable|string',
|
||||
'referenceNo' => 'nullable|string',
|
||||
'note' => 'nullable|string',
|
||||
'payments' => 'required|array|min:1',
|
||||
'payments.*.type' => 'required|string',
|
||||
'payments.*.amount' => 'nullable|numeric|min:0',
|
||||
], [
|
||||
'payments.required' => 'At least one payment method is required.',
|
||||
'payments.*.type.required' => 'Each payment must have a type.',
|
||||
'payments.*.amount.numeric' => 'Each payment amount must be numeric.',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
|
||||
updateBalance($request->amount, 'decrement');
|
||||
|
||||
$data = Expense::create($request->except('status','paymentType') + [
|
||||
'user_id' => auth()->id(),
|
||||
'business_id' => auth()->user()->business_id,
|
||||
]);
|
||||
|
||||
event(new MultiPaymentProcessed(
|
||||
$request->payments ?? [],
|
||||
$data->id,
|
||||
'expense',
|
||||
$request->amount ?? 0,
|
||||
));
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json(['message' => $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
76
app/Http/Controllers/Api/AcnooIncomeCategoryController.php
Normal file
76
app/Http/Controllers/Api/AcnooIncomeCategoryController.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\IncomeCategory;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AcnooIncomeCategoryController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$data = IncomeCategory::where('business_id', auth()->user()->business_id)->latest()->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'categoryName' => 'required|unique:income_categories,categoryName,NULL,id,business_id,' . auth()->user()->business_id,
|
||||
]);
|
||||
|
||||
$data = IncomeCategory::create($request->except('status') + [
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'status' => $request->status == 'true' ? 1 : 0,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$category = IncomeCategory::findOrFail($id);
|
||||
|
||||
$request->validate([
|
||||
'categoryName' => [
|
||||
'required',
|
||||
'unique:income_categories,categoryName,' . $category->id . ',id,business_id,' . auth()->user()->business_id,
|
||||
],
|
||||
]);
|
||||
|
||||
$category->update($request->except('status') + [
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'status' => $request->status == 'true' ? 1 : 0,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data updated successfully.'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
$category = IncomeCategory::findOrFail($id);
|
||||
$category->delete();
|
||||
return response()->json([
|
||||
'message' => __('Data deleted successfully.'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
106
app/Http/Controllers/Api/AcnooIncomeController.php
Normal file
106
app/Http/Controllers/Api/AcnooIncomeController.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Income;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Events\MultiPaymentProcessed;
|
||||
|
||||
class AcnooIncomeController extends Controller
|
||||
{
|
||||
Use DateFilterTrait;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
$incomeQuery = Income::with(['category:id,categoryName', 'payment_type:id,name', 'branch:id,name'])->where('business_id', $businessId);
|
||||
|
||||
// Branch filter
|
||||
if ($request->branch_id) {
|
||||
$incomeQuery->where('branch_id', $request->branch_id);
|
||||
}
|
||||
|
||||
// Apply date filter
|
||||
if(request('duration')){
|
||||
$this->applyDateFilter($incomeQuery, request('duration'), 'incomeDate', request('from_date'), request('to_date'));
|
||||
}
|
||||
|
||||
// Search filter
|
||||
if ($request->filled('search')) {
|
||||
$search = $request->search;
|
||||
$incomeQuery->where(function ($query) use ($search) {
|
||||
$query->where('incomeFor', 'like', '%' . $search . '%')
|
||||
->orWhere('paymentType', 'like', '%' . $search . '%')
|
||||
->orWhere('amount', 'like', '%' . $search . '%')
|
||||
->orWhere('referenceNo', 'like', '%' . $search . '%')
|
||||
->orWhereHas('category', fn($q) => $q->where('categoryName', 'like', '%' . $search . '%'))
|
||||
->orWhereHas('payment_type', fn($q) => $q->where('name', 'like', '%' . $search . '%'))
|
||||
->orWhereHas('branch', fn($q) => $q->where('name', 'like', '%' . $search . '%'));
|
||||
});
|
||||
}
|
||||
|
||||
$data = $incomeQuery->latest()->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'income_category_id' => 'required|exists:income_categories,id',
|
||||
'incomeFor' => 'nullable|string',
|
||||
'referenceNo' => 'nullable|string',
|
||||
'note' => 'nullable|string',
|
||||
'payments' => 'required|array|min:1',
|
||||
'payments.*.type' => 'required|string',
|
||||
'payments.*.amount' => 'nullable|numeric|min:0',
|
||||
'payments.*.cheque_number' => 'nullable|string',
|
||||
], [
|
||||
'payments.required' => 'At least one payment method is required.',
|
||||
'payments.*.type.required' => 'Each payment must have a type.',
|
||||
'payments.*.amount.numeric' => 'Each payment amount must be numeric.',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$total_amount = collect($request->payments)
|
||||
->reject(fn($p) => strtolower($p['type'] ?? '') == 'cheque')
|
||||
->sum(fn($p) => $p['amount'] ?? 0);
|
||||
|
||||
updateBalance($total_amount, 'decrement');
|
||||
|
||||
$data = Income::create($request->except('status', 'amount', 'paymentType') + [
|
||||
'user_id' => auth()->id(),
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'amount' => $total_amount,
|
||||
]);
|
||||
|
||||
event(new MultiPaymentProcessed(
|
||||
$request->payments ?? [],
|
||||
$data->id,
|
||||
'income',
|
||||
$total_amount ?? 0,
|
||||
));
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json(['message' => $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
64
app/Http/Controllers/Api/AcnooInvoiceController.php
Normal file
64
app/Http/Controllers/Api/AcnooInvoiceController.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\DueCollect;
|
||||
use App\Models\Party;
|
||||
use App\Models\Purchase;
|
||||
use App\Models\Sale;
|
||||
use App\Models\SaleReturn;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AcnooInvoiceController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'party_id' => 'required|exists:parties,id'
|
||||
]);
|
||||
|
||||
$party = Party::select('id', 'due', 'name', 'type')->find(request('party_id'));
|
||||
|
||||
if ($party->type == 'Supplier')
|
||||
{
|
||||
$data = $party->load('purchases_dues:id,party_id,dueAmount,paidAmount,totalAmount,invoiceNumber');
|
||||
} else {
|
||||
$data = $party->load('sales_dues:id,party_id,dueAmount,paidAmount,totalAmount,invoiceNumber');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function newInvoice(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'platform' => 'required|in:sales,purchases,due_collects,sales_return,purchases_return'
|
||||
]);
|
||||
|
||||
if ($request->platform == 'sales') {
|
||||
$prefix = 'S-';
|
||||
$id = Sale::where('business_id', auth()->user()->business_id)->count();
|
||||
} elseif ($request->platform == 'purchases') {
|
||||
$prefix = 'P-';
|
||||
$id = Purchase::where('business_id', auth()->user()->business_id)->count();
|
||||
} elseif ($request->platform == 'sales_return') {
|
||||
$prefix = 'SR-';
|
||||
$id = SaleReturn::where('business_id', auth()->user()->business_id)->count();
|
||||
} elseif ($request->platform == 'purchases_return') {
|
||||
// $prefix = 'PR-';
|
||||
// $id = Purchase::where('business_id', auth()->user()->business_id)->count();
|
||||
}
|
||||
else {
|
||||
$prefix = 'D-';
|
||||
$id = DueCollect::where('business_id', auth()->user()->business_id)->count();
|
||||
}
|
||||
|
||||
$invoice = $prefix . str_pad($id + 1, 5, '0', STR_PAD_LEFT);
|
||||
|
||||
return response()->json($invoice);
|
||||
}
|
||||
}
|
||||
33
app/Http/Controllers/Api/AcnooLanguageController.php
Normal file
33
app/Http/Controllers/Api/AcnooLanguageController.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AcnooLanguageController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$data = json_decode(file_get_contents(base_path('lang/langlist.json')), true);
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'lang' => 'required|max:30|min:1|string'
|
||||
]);
|
||||
|
||||
auth()->user()->update([
|
||||
'lang' => $request->lang
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Language updated successfully.')
|
||||
]);
|
||||
}
|
||||
}
|
||||
18
app/Http/Controllers/Api/AcnooPrivacyController.php
Normal file
18
app/Http/Controllers/Api/AcnooPrivacyController.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Option;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AcnooPrivacyController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$policy = Option::where('key', 'policy')->first()->value;
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $policy ?? 'Privacy Policy',
|
||||
]);
|
||||
}
|
||||
}
|
||||
485
app/Http/Controllers/Api/AcnooProductController.php
Normal file
485
app/Http/Controllers/Api/AcnooProductController.php
Normal file
@@ -0,0 +1,485 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\ComboProduct;
|
||||
use App\Models\Stock;
|
||||
use App\Models\Product;
|
||||
use App\Helpers\HasUploader;
|
||||
use App\Models\Vat;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class AcnooProductController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
$products = Product::with([
|
||||
'unit:id,unitName',
|
||||
'vat:id,rate',
|
||||
'brand:id,brandName',
|
||||
'category:id,categoryName',
|
||||
'product_model:id,name',
|
||||
'stocks',
|
||||
'combo_products.stock.product' => function ($query) {
|
||||
$query->select('id', 'productName', 'productCode');
|
||||
},
|
||||
'rack:id,name',
|
||||
'shelf:id,name'
|
||||
])
|
||||
->where(function ($query) {
|
||||
$query->where(function ($q) {
|
||||
$q->where('product_type', '!=', 'combo')
|
||||
->whereHas('stocks');
|
||||
})
|
||||
->orWhere(function ($q) {
|
||||
$q->where('product_type', 'combo')
|
||||
->whereHas('combo_products');
|
||||
});
|
||||
})
|
||||
->withSum('saleDetails', 'quantities')
|
||||
->withSum('purchaseDetails', 'quantities')
|
||||
->withSum('stocks', 'productStock')
|
||||
->where('business_id', $user->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
$total_stock_value = $products->sum(function ($product) {
|
||||
return $product->stocks->sum(function ($stock) {
|
||||
return $stock->productPurchasePrice * $stock->productStock;
|
||||
});
|
||||
});
|
||||
|
||||
$products = $products->map(function ($product) {
|
||||
$product->total_sale_amount = $product->saleDetails->sum(function ($sale) {
|
||||
return ($sale->price - $sale->discount) * $sale->quantities;
|
||||
});
|
||||
|
||||
$product->total_profit_loss = $product->saleDetails->sum(function ($sale) {
|
||||
// If lossProfit column exists, use it
|
||||
if (!is_null($sale->lossProfit)) {
|
||||
return $sale->lossProfit;
|
||||
}
|
||||
// Otherwise calculate: (price - discount - purchase price) * quantity
|
||||
return (($sale->price - $sale->discount) - $sale->productPurchasePrice) * $sale->quantities;
|
||||
});
|
||||
|
||||
return $product;
|
||||
});
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'total_stock_value' => $total_stock_value,
|
||||
'data' => $products,
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
if (is_string($request->stocks)) {
|
||||
$request->merge(['stocks' => json_decode($request->stocks, true)]);
|
||||
}
|
||||
|
||||
if (is_string($request->warranty_guarantee_info)) {
|
||||
$request->merge(['warranty_guarantee_info' => json_decode($request->warranty_guarantee_info, true)]);
|
||||
}
|
||||
|
||||
if (is_string($request->combo_products)) {
|
||||
$request->merge(['combo_products' => json_decode($request->combo_products, true)]);
|
||||
}
|
||||
|
||||
if (is_string($request->variation_ids)) {
|
||||
$decoded = json_decode($request->variation_ids, true);
|
||||
$request->merge(['variation_ids' => $decoded]);
|
||||
}
|
||||
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$request->validate([
|
||||
'vat_id' => 'nullable|exists:vats,id',
|
||||
'unit_id' => 'nullable|exists:units,id',
|
||||
'brand_id' => 'nullable|exists:brands,id',
|
||||
'category_id' => 'nullable|exists:categories,id',
|
||||
'model_id' => 'nullable|exists:product_models,id',
|
||||
'vat_type' => 'nullable|in:inclusive,exclusive',
|
||||
'productName' => 'required|string|max:255',
|
||||
'productPicture' => 'nullable|image|mimes:jpg,png,jpeg,svg',
|
||||
'productCode' => [
|
||||
'nullable',
|
||||
Rule::unique('products')->where(function ($query) use ($business_id) {
|
||||
return $query->where('business_id', $business_id);
|
||||
}),
|
||||
],
|
||||
'alert_qty' => 'nullable|numeric|min:0',
|
||||
'size' => 'nullable|string|max:255',
|
||||
'type' => 'nullable|string|max:255',
|
||||
'color' => 'nullable|string|max:255',
|
||||
'weight' => 'nullable|string|max:255',
|
||||
'capacity' => 'nullable|string|max:255',
|
||||
'productManufacturer' => 'nullable|string|max:255',
|
||||
'product_type' => 'required|in:single,variant,combo',
|
||||
'variation_ids' => 'nullable|array',
|
||||
'variation_ids.*' => 'exists:variations,id',
|
||||
|
||||
'stocks.*.warehouse_id' => 'nullable|exists:warehouses,id',
|
||||
'stocks.*.productStock' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.exclusive_price' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.inclusive_price' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.profit_percent' => 'nullable|numeric|max:99999999.99',
|
||||
'stocks.*.productSalePrice' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.productWholeSalePrice' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.productDealerPrice' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.mfg_date' => 'nullable|date',
|
||||
'stocks.*.expire_date' => 'nullable|date|after_or_equal:stocks.*.mfg_date',
|
||||
'stocks' => 'nullable|array',
|
||||
'stocks.*.batch_no' => [
|
||||
'nullable',
|
||||
function ($attribute, $value, $fail) use ($request) {
|
||||
$batchNos = collect($request->stocks)->pluck('batch_no')->filter()->toArray();
|
||||
|
||||
if (count($batchNos) !== count(array_unique($batchNos))) {
|
||||
$fail('Duplicate batch number found in the request.');
|
||||
}
|
||||
},
|
||||
],
|
||||
|
||||
// Combo validation
|
||||
'combo_products' => 'nullable|array',
|
||||
'combo_products.*.stock_id' => [
|
||||
'required_if:product_type,combo',
|
||||
Rule::exists('stocks', 'id')->where('business_id', $business_id),
|
||||
],
|
||||
'combo_products.*.quantity' => 'required_if:product_type,combo|numeric|min:1',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
// vat calculation
|
||||
$vat = Vat::find($request->vat_id);
|
||||
$vat_rate = $vat->rate ?? 0;
|
||||
|
||||
// Create the product
|
||||
$product = Product::create($request->only('productName', 'unit_id', 'brand_id', 'vat_id', 'vat_type', 'category_id', 'productCode', 'product_type', 'rack_id', 'shelf_id', 'model_id', 'variation_ids', 'warranty_guarantee_info') + [
|
||||
'business_id' => $business_id,
|
||||
'alert_qty' => $request->alert_qty ?? 0,
|
||||
'profit_percent' => $request->product_type == 'combo' ? $request->profit_percent ?? 0 : 0,
|
||||
'productSalePrice' => $request->product_type == 'combo' ? $request->productSalePrice ?? 0 : 0,
|
||||
'productPicture' => $request->productPicture ? $this->upload($request, 'productPicture') : NULL,
|
||||
]);
|
||||
|
||||
// Single or Variant Product
|
||||
if (in_array($request->product_type, ['single', 'variant']) && !empty($request->stocks)) {
|
||||
$stockData = [];
|
||||
foreach ($request->stocks as $stock) {
|
||||
|
||||
$base_price = $stock['exclusive_price'] ?? 0;
|
||||
$purchasePrice = $request->vat_type === 'inclusive'
|
||||
? $base_price + ($base_price * $vat_rate / 100)
|
||||
: $base_price;
|
||||
|
||||
$stockData[] = [
|
||||
'business_id' => $business_id,
|
||||
'product_id' => $product->id,
|
||||
'batch_no' => $stock['batch_no'] ?? null,
|
||||
'warehouse_id' => $stock['warehouse_id'] ?? null,
|
||||
'productStock' => $stock['productStock'] ?? 0,
|
||||
'productPurchasePrice' => $purchasePrice,
|
||||
'profit_percent' => $stock['profit_percent'] ?? 0,
|
||||
'productSalePrice' => $stock['productSalePrice'] ?? 0,
|
||||
'productWholeSalePrice' => $stock['productWholeSalePrice'] ?? 0,
|
||||
'productDealerPrice' => $stock['productDealerPrice'] ?? 0,
|
||||
'mfg_date' => $stock['mfg_date'] ?? null,
|
||||
'expire_date' => $stock['expire_date'] ?? null,
|
||||
'variation_data' => isset($stock['variation_data']) ? json_encode($stock['variation_data']) : null,
|
||||
'variant_name' => $stock['variant_name'] ?? null,
|
||||
'serial_numbers' => $stock['serial_numbers'] ?? null,
|
||||
'branch_id' => auth()->user()->branch_id ?? auth()->user()->active_branch_id,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
];
|
||||
}
|
||||
|
||||
Stock::insert($stockData);
|
||||
}
|
||||
|
||||
// Combo Product
|
||||
if ($request->product_type === 'combo' && !empty($request->combo_products)) {
|
||||
foreach ($request->combo_products as $item) {
|
||||
ComboProduct::create([
|
||||
'product_id' => $product->id,
|
||||
'stock_id' => $item['stock_id'],
|
||||
'quantity' => $item['quantity'],
|
||||
'purchase_price' => $item['purchase_price'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $product
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json([
|
||||
'message' => $e->getMessage(),
|
||||
], 406);
|
||||
}
|
||||
}
|
||||
|
||||
public function show(string $id)
|
||||
{
|
||||
$data = Product::with([
|
||||
'unit:id,unitName',
|
||||
'vat:id,rate',
|
||||
'brand:id,brandName',
|
||||
'category:id,categoryName',
|
||||
'product_model:id,name',
|
||||
'stocks',
|
||||
'stocks.warehouse:id,name',
|
||||
'combo_products.stock.product' => function ($query) {
|
||||
$query->select('id', 'productName', 'productCode');
|
||||
},
|
||||
'rack:id,name',
|
||||
'shelf:id,name'
|
||||
])
|
||||
->withSum('saleDetails', 'quantities')
|
||||
->withSum('purchaseDetails', 'quantities')
|
||||
->withSum('stocks', 'productStock')
|
||||
->findOrFail($id);
|
||||
|
||||
$data->total_sale_amount = $data->saleDetails->sum(function ($sale) {
|
||||
return ($sale->price - $sale->discount) * $sale->quantities;
|
||||
});
|
||||
|
||||
$data->total_profit_loss = $data->saleDetails->sum(function ($sale) {
|
||||
if (!is_null($sale->lossProfit)) {
|
||||
return $sale->lossProfit;
|
||||
}
|
||||
return (($sale->price - $sale->discount) - $sale->productPurchasePrice) * $sale->quantities;
|
||||
});
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, Product $product)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
if ($product->product_type != $request->product_type) {
|
||||
return response()->json([
|
||||
'message' => __('Product type can not be changed.'),
|
||||
], 406);
|
||||
}
|
||||
|
||||
if (is_string($request->stocks)) {
|
||||
$request->merge(['stocks' => json_decode($request->stocks, true)]);
|
||||
}
|
||||
|
||||
if (is_string($request->warranty_guarantee_info)) {
|
||||
$request->merge(['warranty_guarantee_info' => json_decode($request->warranty_guarantee_info, true)]);
|
||||
}
|
||||
|
||||
if (is_string($request->combo_products)) {
|
||||
$request->merge(['combo_products' => json_decode($request->combo_products, true)]);
|
||||
}
|
||||
|
||||
if (is_string($request->variation_ids)) {
|
||||
$request->merge(['variation_ids' => json_decode($request->variation_ids, true)]);
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
'vat_id' => 'nullable|exists:vats,id',
|
||||
'unit_id' => 'nullable|exists:units,id',
|
||||
'brand_id' => 'nullable|exists:brands,id',
|
||||
'category_id' => 'nullable|exists:categories,id',
|
||||
'model_id' => 'nullable|exists:product_models,id',
|
||||
'vat_type' => 'nullable|in:inclusive,exclusive',
|
||||
'productName' => 'required|string|max:255',
|
||||
'productPicture' => 'nullable|image|mimes:jpg,png,jpeg,svg',
|
||||
'productCode' => [
|
||||
'nullable',
|
||||
Rule::unique('products', 'productCode')->ignore($product->id)->where(function ($query) use ($business_id) {
|
||||
return $query->where('business_id', $business_id);
|
||||
}),
|
||||
],
|
||||
'alert_qty' => 'nullable|numeric|min:0',
|
||||
'size' => 'nullable|string|max:255',
|
||||
'type' => 'nullable|string|max:255',
|
||||
'color' => 'nullable|string|max:255',
|
||||
'weight' => 'nullable|string|max:255',
|
||||
'capacity' => 'nullable|string|max:255',
|
||||
'productManufacturer' => 'nullable|string|max:255',
|
||||
'product_type' => 'required|in:single,variant,combo',
|
||||
'variation_ids' => 'nullable|array',
|
||||
'variation_ids.*' => 'exists:variations,id',
|
||||
|
||||
'stocks.*.warehouse_id' => 'nullable|exists:warehouses,id',
|
||||
'stocks.*.productStock' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.exclusive_price' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.inclusive_price' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.profit_percent' => 'nullable|numeric|max:99999999.99',
|
||||
'stocks.*.productSalePrice' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.productWholeSalePrice' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.productDealerPrice' => 'nullable|numeric|min:0|max:99999999.99',
|
||||
'stocks.*.mfg_date' => 'nullable|date',
|
||||
'stocks.*.expire_date' => 'nullable|date|after_or_equal:stocks.*.mfg_date',
|
||||
'stocks' => 'nullable|array',
|
||||
'stocks.*.batch_no' => [
|
||||
'nullable',
|
||||
function ($attribute, $value, $fail) use ($request) {
|
||||
$batchNos = collect($request->stocks)->pluck('batch_no')->filter()->toArray();
|
||||
|
||||
if (count($batchNos) !== count(array_unique($batchNos))) {
|
||||
$fail('Duplicate batch number found in the request.');
|
||||
}
|
||||
},
|
||||
],
|
||||
|
||||
// Combo validation
|
||||
'combo_products' => 'nullable|array',
|
||||
'combo_products.*.stock_id' => [
|
||||
'required_if:product_type,combo',
|
||||
Rule::exists('stocks', 'id')->where('business_id', $business_id),
|
||||
],
|
||||
'combo_products.*.quantity' => 'required_if:product_type,combo|numeric|min:1',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
// VAT calculation
|
||||
$vat = Vat::find($request->vat_id);
|
||||
$vat_rate = $vat->rate ?? 0;
|
||||
|
||||
// Update product
|
||||
$product->update($request->except(['productPicture', 'productPurchasePrice', 'productDealerPrice', 'productWholeSalePrice', 'alert_qty', 'stocks', 'vat_amount', 'profit_percent']) + [
|
||||
'business_id' => $business_id,
|
||||
'alert_qty' => $request->alert_qty ?? 0,
|
||||
'profit_percent' => $request->profit_percent ?? 0,
|
||||
'productPicture' => $request->productPicture ? $this->upload($request, 'productPicture', $product->productPicture) : $product->productPicture,
|
||||
]);
|
||||
|
||||
// Delete previous stocks and combos
|
||||
if ($product->product_type === 'combo') {
|
||||
ComboProduct::where('product_id', $product->id)->delete();
|
||||
}
|
||||
|
||||
// Handle Single/Variant Product Stocks
|
||||
if (in_array($request->product_type, ['single', 'variant']) && !empty($request->stocks)) {
|
||||
$existingStockIds = $product->stocks()->pluck('id')->toArray();
|
||||
$incomingStockIds = collect($request->stocks)->pluck('stock_id')->filter()->toArray();
|
||||
|
||||
// Delete removed stocks
|
||||
$stocksToDelete = array_diff($existingStockIds, $incomingStockIds);
|
||||
Stock::whereIn('id', $stocksToDelete)->delete();
|
||||
|
||||
// Insert or Update
|
||||
foreach ($request->stocks as $stock) {
|
||||
// Decode variation_data if sent as string
|
||||
if (isset($stock['variation_data']) && is_string($stock['variation_data'])) {
|
||||
$stock['variation_data'] = json_decode($stock['variation_data'], true);
|
||||
}
|
||||
|
||||
$stockId = $stock['stock_id'] ?? null;
|
||||
|
||||
// Recalculate price
|
||||
$base_price = $stock['exclusive_price'] ?? 0;
|
||||
$purchasePrice = $request->vat_type === 'inclusive'
|
||||
? $base_price + ($base_price * $vat_rate / 100)
|
||||
: $base_price;
|
||||
|
||||
$payload = [
|
||||
'business_id' => $business_id,
|
||||
'product_id' => $product->id,
|
||||
'batch_no' => $stock['batch_no'] ?? null,
|
||||
'warehouse_id' => $stock['warehouse_id'] ?? null,
|
||||
'productStock' => $stock['productStock'] ?? 0,
|
||||
'productPurchasePrice' => $purchasePrice,
|
||||
'profit_percent' => $stock['profit_percent'] ?? 0,
|
||||
'productSalePrice' => $stock['productSalePrice'] ?? 0,
|
||||
'productWholeSalePrice' => $stock['productWholeSalePrice'] ?? 0,
|
||||
'productDealerPrice' => $stock['productDealerPrice'] ?? 0,
|
||||
'mfg_date' => $stock['mfg_date'] ?? null,
|
||||
'expire_date' => $stock['expire_date'] ?? null,
|
||||
'variation_data' => $stock['variation_data'] ?? null,
|
||||
'variant_name' => $stock['variant_name'] ?? null,
|
||||
'branch_id' => auth()->user()->branch_id ?? auth()->user()->active_branch_id,
|
||||
'serial_numbers' => $request->has_serial ? $stock['serial_numbers'] : null,
|
||||
];
|
||||
|
||||
if ($stockId) {
|
||||
Stock::where('id', $stockId)->update($payload);
|
||||
} else {
|
||||
Stock::create($payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Combo Product
|
||||
if ($request->product_type === 'combo' && !empty($request->combo_products)) {
|
||||
foreach ($request->combo_products as $item) {
|
||||
ComboProduct::create([
|
||||
'product_id' => $product->id,
|
||||
'stock_id' => $item['stock_id'],
|
||||
'quantity' => $item['quantity'],
|
||||
'purchase_price' => $item['purchase_price'] ?? 0,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $product->load('stocks'),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json([
|
||||
'message' => $e->getMessage()
|
||||
], 406);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(Product $product)
|
||||
{
|
||||
if (file_exists($product->productPicture)) {
|
||||
Storage::delete($product->productPicture);
|
||||
}
|
||||
$product->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data deleted successfully.'),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function generateCode()
|
||||
{
|
||||
$product_id = (Product::where('business_id', auth()->user()->business_id)->count() ?? 0) + 1;
|
||||
$code = str_pad($product_id, 4, '0', STR_PAD_LEFT);
|
||||
|
||||
return response()->json([
|
||||
'data' => $code,
|
||||
]);
|
||||
}
|
||||
}
|
||||
83
app/Http/Controllers/Api/AcnooProfileController.php
Normal file
83
app/Http/Controllers/Api/AcnooProfileController.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Helpers\HasUploader;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class AcnooProfileController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
public function index()
|
||||
{
|
||||
$user = User::with('business')->findOrFail(auth()->id());
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $user
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|max:250',
|
||||
'email' => ['required', 'email', Rule::unique('users')->ignore(auth()->id())],
|
||||
'image' => 'nullable|image|mimes:jpeg,png,gif|dimensions:max_width=2000,max_height=2000|max:1048',
|
||||
]);
|
||||
|
||||
$user = User::findOrFail(auth()->id());
|
||||
|
||||
$user->update($request->except('image') + [
|
||||
'image' => $request->image ? $this->upload($request, 'image', $user->image) : $user->image,
|
||||
]);
|
||||
|
||||
$user = User::findOrFail(auth()->id());
|
||||
|
||||
$data = [
|
||||
'name' => $user->name,
|
||||
'email' => $user->email,
|
||||
'phone' => $user->phone,
|
||||
'image' => $user->image,
|
||||
];
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Profile updated successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function changePassword(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'current_password' => 'required',
|
||||
'password' => 'required|string|min:6',
|
||||
]);
|
||||
|
||||
$user = auth()->user();
|
||||
|
||||
if ($request->current_password == $request->password){
|
||||
return response()->json([
|
||||
'message' => __('You have already used this password.')
|
||||
], 422);
|
||||
}
|
||||
|
||||
if (!Hash::check($request->current_password, $user->password)) {
|
||||
return response()->json([
|
||||
'message' => __('Current password does not match with old password.')
|
||||
], 422);
|
||||
}
|
||||
|
||||
$user->update([
|
||||
'password' => Hash::make($request->password),
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Password changed successfully.'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
534
app/Http/Controllers/Api/AcnooReportController.php
Normal file
534
app/Http/Controllers/Api/AcnooReportController.php
Normal file
@@ -0,0 +1,534 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Vat;
|
||||
use App\Models\Sale;
|
||||
use App\Models\Product;
|
||||
use App\Models\Purchase;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\Transaction;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\PlanSubscribe;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AcnooReportController extends Controller
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function lossProfit(Request $request)
|
||||
{
|
||||
$user = auth()->user();
|
||||
$businessId = $user->business_id;
|
||||
|
||||
$branchId = null;
|
||||
if (moduleCheck('MultiBranchAddon')) {
|
||||
$branchId = $user->branch_id ?? $user->active_branch_id;
|
||||
}
|
||||
|
||||
$duration = $request->duration ?: 'today';
|
||||
|
||||
|
||||
$salesQuery = DB::table('sales')
|
||||
->select(
|
||||
DB::raw('DATE(saleDate) as date'),
|
||||
DB::raw('SUM(actual_total_amount) as total_sales'),
|
||||
DB::raw('SUM(lossProfit) as total_sale_income')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn($q) => $q->where('branch_id', $branchId))
|
||||
->groupBy(DB::raw('DATE(saleDate)'));
|
||||
|
||||
|
||||
$this->applyDateFilter($salesQuery, $duration, 'saleDate', $request->from_date, $request->to_date);
|
||||
|
||||
|
||||
$dailySales = $salesQuery->get();
|
||||
|
||||
$sale_datas = $dailySales->map(fn($sale) => (object)[
|
||||
'type' => 'Sale',
|
||||
'date' => $sale->date,
|
||||
'total_sales' => $sale->total_sales,
|
||||
'total_incomes' => $sale->total_sale_income,
|
||||
]);
|
||||
|
||||
$incomeQuery = DB::table('incomes')
|
||||
->select(
|
||||
DB::raw('DATE(incomeDate) as date'),
|
||||
DB::raw('SUM(amount) as total_incomes')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn($q) => $q->where('branch_id', $branchId))
|
||||
->groupBy(DB::raw('DATE(incomeDate)'));
|
||||
|
||||
$this->applyDateFilter($incomeQuery, $duration, 'incomeDate', $request->from_date, $request->to_date);
|
||||
$dailyIncomes = $incomeQuery->get();
|
||||
|
||||
$income_datas = $dailyIncomes->map(fn($income) => (object)[
|
||||
'type' => 'Income',
|
||||
'date' => $income->date,
|
||||
'total_incomes' => $income->total_incomes,
|
||||
]);
|
||||
|
||||
$mergedIncomeSaleData = collect();
|
||||
$allDates = $dailySales->pluck('date')
|
||||
->merge($dailyIncomes->pluck('date'))
|
||||
->unique()
|
||||
->sort();
|
||||
|
||||
foreach ($allDates as $date) {
|
||||
if ($income = $income_datas->firstWhere('date', $date)) {
|
||||
$mergedIncomeSaleData->push($income);
|
||||
}
|
||||
if ($sale = $sale_datas->firstWhere('date', $date)) {
|
||||
$mergedIncomeSaleData->push($sale);
|
||||
}
|
||||
}
|
||||
|
||||
$dailyPayrolls = collect();
|
||||
|
||||
if (moduleCheck('HrmAddon')) {
|
||||
$payrollQuery = DB::table('payrolls')
|
||||
->select(
|
||||
DB::raw('DATE(date) as date'),
|
||||
DB::raw('SUM(amount) as total_payrolls')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn($q) => $q->where('branch_id', $branchId))
|
||||
->groupBy(DB::raw('DATE(date)'));
|
||||
|
||||
$this->applyDateFilter($payrollQuery, $duration, 'date', $request->from_date, $request->to_date);
|
||||
$dailyPayrolls = $payrollQuery->get();
|
||||
}
|
||||
|
||||
$expenseQuery = DB::table('expenses')
|
||||
->select(
|
||||
DB::raw('DATE(expenseDate) as date'),
|
||||
DB::raw('SUM(amount) as total_expenses_only')
|
||||
)
|
||||
->where('business_id', $businessId)
|
||||
->when($branchId, fn($q) => $q->where('branch_id', $branchId))
|
||||
->groupBy(DB::raw('DATE(expenseDate)'));
|
||||
|
||||
$this->applyDateFilter($expenseQuery, $duration, 'expenseDate', $request->from_date, $request->to_date);
|
||||
$dailyExpenses = $expenseQuery->get();
|
||||
|
||||
$mergedExpenseData = collect();
|
||||
$allExpenseDates = $dailyExpenses->pluck('date')
|
||||
->merge($dailyPayrolls->pluck('date'))
|
||||
->unique()
|
||||
->sort();
|
||||
|
||||
foreach ($allExpenseDates as $date) {
|
||||
if ($expense = $dailyExpenses->firstWhere('date', $date)) {
|
||||
$mergedExpenseData->push((object)[
|
||||
'type' => 'Expense',
|
||||
'date' => $date,
|
||||
'total_expenses' => $expense->total_expenses_only,
|
||||
]);
|
||||
}
|
||||
|
||||
if ($payroll = $dailyPayrolls->firstWhere('date', $date)) {
|
||||
$mergedExpenseData->push((object)[
|
||||
'type' => 'Payroll',
|
||||
'date' => $date,
|
||||
'total_expenses' => $payroll->total_payrolls,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$grossSaleProfit = $sale_datas->sum('total_sales');
|
||||
$grossIncomeProfit = $income_datas->sum('total_incomes') + $sale_datas->sum('total_incomes');
|
||||
$totalExpenses = $mergedExpenseData->sum('total_expenses');
|
||||
$netProfit = $grossIncomeProfit - $totalExpenses;
|
||||
|
||||
$allTimeIncomes = DB::table('incomes')->where('business_id', $businessId)
|
||||
->when($branchId, fn($q) => $q->where('branch_id', $branchId))
|
||||
->sum('amount');
|
||||
|
||||
$allTimeSaleProfit = DB::table('sales')->where('business_id', $businessId)
|
||||
->when($branchId, fn($q) => $q->where('branch_id', $branchId))
|
||||
->sum('lossProfit');
|
||||
|
||||
$allTimePayrolls = moduleCheck('HrmAddon')
|
||||
? DB::table('payrolls')->where('business_id', $businessId)
|
||||
->when($branchId, fn($q) => $q->where('branch_id', $branchId))
|
||||
->sum('amount')
|
||||
: 0;
|
||||
|
||||
$allTimeExpensesOnly = DB::table('expenses')->where('business_id', $businessId)
|
||||
->when($branchId, fn($q) => $q->where('branch_id', $branchId))
|
||||
->sum('amount');
|
||||
|
||||
$cardGrossProfit = $allTimeIncomes + $allTimeSaleProfit;
|
||||
$totalCardExpenses = $allTimePayrolls + $allTimeExpensesOnly;
|
||||
$cardNetProfit = $cardGrossProfit - $totalCardExpenses;
|
||||
|
||||
return response()->json([
|
||||
'mergedIncomeSaleData' => $mergedIncomeSaleData->values(),
|
||||
'mergedExpenseData' => $mergedExpenseData->values(),
|
||||
'grossSaleProfit' => $grossSaleProfit,
|
||||
'grossIncomeProfit' => $grossIncomeProfit,
|
||||
'totalExpenses' => $totalExpenses,
|
||||
'netProfit' => $netProfit,
|
||||
'cardGrossProfit' => $cardGrossProfit,
|
||||
'totalCardExpenses' => $totalCardExpenses,
|
||||
'cardNetProfit' => $cardNetProfit,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function cashFlow(Request $request)
|
||||
{
|
||||
$query = Transaction::with([
|
||||
'paymentType:id,name',
|
||||
'sale:id,party_id',
|
||||
'sale.party:id,name',
|
||||
'saleReturn:id,sale_id',
|
||||
'purchase:id,party_id',
|
||||
'purchase.party:id,name',
|
||||
'purchaseReturn:id,purchase_id',
|
||||
'dueCollect:id,party_id',
|
||||
'dueCollect.party:id,name',
|
||||
])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->whereIn('type', ['debit', 'credit']);
|
||||
|
||||
$total_cash_in = (clone $query)
|
||||
->where('type', 'credit')
|
||||
->sum('amount');
|
||||
|
||||
$total_cash_out = (clone $query)
|
||||
->where('type', 'debit')
|
||||
->sum('amount');
|
||||
|
||||
$total_running_cash = $total_cash_in - $total_cash_out;
|
||||
|
||||
// Apply date filter
|
||||
$duration = $request->duration ?: 'today';
|
||||
$this->applyDateFilter($query, $duration, 'date', $request->from_date, $request->to_date);
|
||||
$cash_flows = $query->get();
|
||||
|
||||
$firstDate = $cash_flows->first()?->date;
|
||||
|
||||
if ($firstDate) {
|
||||
$opening_balance = (clone $query)
|
||||
->whereDate('date', '<', $firstDate)
|
||||
->selectRaw("SUM(CASE WHEN type='credit' THEN amount ELSE 0 END) - SUM(CASE WHEN type='debit' THEN amount ELSE 0 END) as balance")
|
||||
->value('balance') ?? 0;
|
||||
} else {
|
||||
$opening_balance = 0;
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'cash_in' => $total_cash_in,
|
||||
'cash_out' => $total_cash_out,
|
||||
'running_cash' => $total_running_cash,
|
||||
'initial_running_cash' => $opening_balance,
|
||||
'data' => $cash_flows,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function balanceSheetReport(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$duration = $request->duration ?: 'today';
|
||||
$fromDate = $request->from_date;
|
||||
$toDate = $request->to_date;
|
||||
|
||||
$productQuery = Product::select('id', 'business_id', 'productName', 'product_type', 'created_at')
|
||||
->with(['stocks:id,business_id,product_id,productStock,productPurchasePrice', 'combo_products.stock'])
|
||||
->where('business_id', $businessId);
|
||||
|
||||
$this->applyDateFilter($productQuery, $duration, 'created_at', $fromDate, $toDate);
|
||||
|
||||
$products = $productQuery->get()
|
||||
->map(function ($item) {
|
||||
$item->source = 'product';
|
||||
return $item;
|
||||
});
|
||||
|
||||
$bankQuery = PaymentType::where('business_id', $businessId);
|
||||
|
||||
$this->applyDateFilter($bankQuery, $duration, 'opening_date', $fromDate, $toDate);
|
||||
|
||||
$banks = $bankQuery->get()
|
||||
->map(function ($item) {
|
||||
$item->source = 'bank';
|
||||
return $item;
|
||||
});
|
||||
|
||||
$product_bank_datas = $products->merge($banks);
|
||||
|
||||
$total_stock_value = 0;
|
||||
|
||||
foreach ($products as $product) {
|
||||
// SINGLE / VARIANT
|
||||
if (in_array($product->product_type, ['single', 'variant'])) {
|
||||
foreach ($product->stocks as $stock) {
|
||||
$total_stock_value += $stock->productStock * $stock->productPurchasePrice;
|
||||
}
|
||||
}
|
||||
|
||||
// COMBO
|
||||
if ($product->product_type === 'combo') {
|
||||
foreach ($product->combo_products as $combo) {
|
||||
$childStock = $combo->stock;
|
||||
if ($childStock) {
|
||||
$total_stock_value += ($childStock->productStock / $combo->quantity) * $combo->purchase_price;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$totalBankBalance = $banks->sum('balance');
|
||||
$total_asset = $total_stock_value + $totalBankBalance;
|
||||
|
||||
return response()->json([
|
||||
'asset_datas' => $product_bank_datas,
|
||||
'total_asset' => $total_asset,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function subscriptionReport(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$duration = $request->duration ?: 'today';
|
||||
$fromDate = $request->from_date;
|
||||
$toDate = $request->to_date;
|
||||
|
||||
$subscriptionQuery = PlanSubscribe::with([
|
||||
'plan:id,subscriptionName',
|
||||
'business:id,companyName,business_category_id,pictureUrl',
|
||||
'business.category:id,name',
|
||||
'gateway:id,name'
|
||||
])->where('business_id', $businessId);
|
||||
|
||||
$this->applyDateFilter($subscriptionQuery, $duration, 'created_at', $fromDate, $toDate);
|
||||
|
||||
$subscriptions = $subscriptionQuery->get();
|
||||
|
||||
return response()->json([
|
||||
'data' => $subscriptions,
|
||||
]);
|
||||
}
|
||||
|
||||
public function taxReport(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$duration = $request->duration ?: 'today';
|
||||
$fromDate = $request->from_date;
|
||||
$toDate = $request->to_date;
|
||||
|
||||
$vats = Vat::where('business_id', $businessId)->whereStatus(1)->get();
|
||||
|
||||
//sales
|
||||
$salesQuery = Sale::with('party:id,name,email,phone,type', 'vat:id,name')
|
||||
->where('business_id', $businessId)
|
||||
->where('vat_amount', '>', 0);
|
||||
|
||||
$this->applyDateFilter($salesQuery, $duration, 'created_at', $fromDate, $toDate);
|
||||
|
||||
$sales = $salesQuery->get()->map(function ($item) {
|
||||
$item->source = 'sale'; // append a source field
|
||||
return $item;
|
||||
});
|
||||
|
||||
$salesTotalAmount = $sales->sum('totalAmount');
|
||||
$salesTotalDiscount = $sales->sum('discountAmount');
|
||||
$salesTotalVat = $sales->sum('vat_amount');
|
||||
|
||||
$salesVatTotals = [];
|
||||
foreach ($vats as $vat) {
|
||||
$salesVatTotals[$vat->id] = $sales->where('vat_id', $vat->id)->sum('vat_amount');
|
||||
}
|
||||
|
||||
//purchase
|
||||
$purchaseQuery = Purchase::with('party:id,name,email,phone,type', 'vat:id,name')
|
||||
->where('business_id', $businessId)
|
||||
->where('vat_amount', '>', 0);
|
||||
|
||||
$this->applyDateFilter($purchaseQuery, $duration, 'created_at', $fromDate, $toDate);
|
||||
|
||||
$purchases = $purchaseQuery->get()->map(function ($item) {
|
||||
$item->source = 'purchase'; // append a source field
|
||||
return $item;
|
||||
});
|
||||
|
||||
$purchasesTotalAmount = $purchases->sum('totalAmount');
|
||||
$purchasesTotalDiscount = $purchases->sum('discountAmount');
|
||||
$purchasesTotalVat = $purchases->sum('vat_amount');
|
||||
|
||||
$purchasesVatTotals = [];
|
||||
foreach ($vats as $vat) {
|
||||
$purchasesVatTotals[$vat->id] = $purchases->where('vat_id', $vat->id)->sum('vat_amount');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'sales' => $sales,
|
||||
'sales_total_amount' => $salesTotalAmount,
|
||||
'sales_total_discount' => $salesTotalDiscount,
|
||||
'sales_total_vat' => $salesTotalVat,
|
||||
'purchases' => $purchases,
|
||||
'purchases_total_amount' => $purchasesTotalAmount,
|
||||
'purchases_total_discount' => $purchasesTotalDiscount,
|
||||
'purchases_total_vat' => $purchasesTotalVat,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function billWiseProfitReport(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$duration = $request->duration ?: 'today';
|
||||
$fromDate = $request->from_date;
|
||||
$toDate = $request->to_date;
|
||||
|
||||
$billQuery = Sale::select('id', 'business_id', 'party_id', 'invoiceNumber', 'saleDate', 'totalAmount', 'lossProfit')
|
||||
->with('party:id,name', 'details:id,sale_id,product_id,price,quantities,productPurchasePrice,lossProfit', 'details.product:id,productName')->where('business_id', $businessId);
|
||||
|
||||
$this->applyDateFilter($billQuery, $duration, 'saleDate', $fromDate, $toDate);
|
||||
$bills = $billQuery->get();
|
||||
|
||||
$total_amount = $bills->sum('totalAmount');
|
||||
$total_bill_profit = $bills
|
||||
->where('lossProfit', '>=', 0)
|
||||
->sum('lossProfit');
|
||||
|
||||
$total_bill_loss = $bills
|
||||
->where('lossProfit', '<', 0)
|
||||
->sum('lossProfit');
|
||||
|
||||
return response()->json([
|
||||
'data' => $bills,
|
||||
'total_amount' => $total_amount,
|
||||
'total_bill_profit' => $total_bill_profit,
|
||||
'total_bill_loss' => $total_bill_loss,
|
||||
]);
|
||||
}
|
||||
|
||||
public function productSaleHistory(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$duration = $request->duration ?: 'today';
|
||||
|
||||
$productQuery = Product::with(['saleDetails', 'purchaseDetails', 'saleDetails.sale', 'stocks', 'combo_products'])
|
||||
->where('business_id', $businessId)
|
||||
->whereHas('saleDetails.sale', function ($sale) use ($duration, $request) {
|
||||
$this->applyDateFilter($sale, $duration, 'saleDate', $request->from_date, $request->to_date);
|
||||
});
|
||||
|
||||
$products = $productQuery->get();
|
||||
|
||||
$total_purchase_qty = $products->sum(function ($product) {
|
||||
return $product->purchaseDetails->sum('quantities');
|
||||
});
|
||||
$total_sale_qty = $products->sum(function ($product) {
|
||||
return $product->saleDetails->sum('quantities');
|
||||
});
|
||||
|
||||
return response()->json([
|
||||
'data' => $products,
|
||||
'total_purchase_qty' => $total_purchase_qty,
|
||||
'total_sale_qty' => $total_sale_qty,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function productSaleHistoryDetails(Request $request, $productId)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$duration = $request->duration ?: 'today';
|
||||
$fromDate = $request->from_date;
|
||||
$toDate = $request->to_date;
|
||||
|
||||
$product = Product::select('id', 'business_id', 'productName')
|
||||
->with([
|
||||
'saleDetails' => function ($q) use ($duration, $fromDate, $toDate) {
|
||||
|
||||
$q->whereHas('sale', function ($sale) use ($duration, $fromDate, $toDate) {
|
||||
$this->applyDateFilter($sale, $duration, 'saleDate', $fromDate, $toDate);
|
||||
});
|
||||
|
||||
$q->select('id', 'sale_id', 'product_id', 'quantities', 'price', 'productPurchasePrice')
|
||||
->with([
|
||||
'sale:id,invoiceNumber,saleDate'
|
||||
]);
|
||||
},
|
||||
])->where('business_id', $businessId)->findOrFail($productId);
|
||||
|
||||
$totalQuantities = $product->saleDetails->sum('quantities');
|
||||
$totalSalePrice = $product->saleDetails->sum('price');
|
||||
$totalPurchasePrice = $product->saleDetails->sum('productPurchasePrice');
|
||||
|
||||
return response()->json([
|
||||
'data' => $product,
|
||||
'total_quantities' => $totalQuantities,
|
||||
'total_sale_price' => $totalSalePrice,
|
||||
'total_purchase_price' => $totalPurchasePrice,
|
||||
]);
|
||||
}
|
||||
|
||||
public function productPurchaseHistory(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$duration = $request->duration ?: 'today';
|
||||
|
||||
$productQuery = Product::with(['saleDetails', 'purchaseDetails', 'purchaseDetails.purchase', 'stocks', 'combo_products'])
|
||||
->where('business_id', $businessId)
|
||||
->whereHas('purchaseDetails.purchase', function ($purchase) use ($duration, $request) {
|
||||
$this->applyDateFilter($purchase, $duration, 'purchaseDate', $request->from_date, $request->to_date);
|
||||
});
|
||||
|
||||
$products = $productQuery->get();
|
||||
|
||||
$total_purchase_qty = $products->sum(function ($product) {
|
||||
return $product->purchaseDetails->sum('quantities');
|
||||
});
|
||||
$total_sale_qty = $products->sum(function ($product) {
|
||||
return $product->saleDetails->sum('quantities');
|
||||
});
|
||||
|
||||
return response()->json([
|
||||
'data' => $products,
|
||||
'total_purchase_qty' => $total_purchase_qty,
|
||||
'total_sale_qty' => $total_sale_qty,
|
||||
]);
|
||||
}
|
||||
|
||||
public function productPurchaseHistoryDetails(Request $request, $productId)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
$duration = $request->duration ?: 'today';
|
||||
$fromDate = $request->from_date;
|
||||
$toDate = $request->to_date;
|
||||
|
||||
$product = Product::select('id', 'business_id', 'productName')
|
||||
->with([
|
||||
'purchaseDetails' => function ($q) use ($duration, $fromDate, $toDate) {
|
||||
|
||||
$q->whereHas('purchase', function ($purchase) use ($duration, $fromDate, $toDate) {
|
||||
$this->applyDateFilter($purchase, $duration, 'purchaseDate', $fromDate, $toDate);
|
||||
});
|
||||
|
||||
$q->select('id', 'purchase_id', 'product_id', 'quantities', 'productPurchasePrice')
|
||||
->with([
|
||||
'purchase:id,invoiceNumber,purchaseDate'
|
||||
]);
|
||||
},
|
||||
])->where('business_id', $businessId)->findOrFail($productId);
|
||||
|
||||
$totalQuantities = $product->purchaseDetails->sum('quantities');
|
||||
$totalPurchasePrice = $product->purchaseDetails->sum('productPurchasePrice');
|
||||
|
||||
return response()->json([
|
||||
'data' => $product,
|
||||
'total_quantities' => $totalQuantities,
|
||||
'total_purchase_price' => $totalPurchasePrice,
|
||||
]);
|
||||
}
|
||||
}
|
||||
561
app/Http/Controllers/Api/AcnooSaleController.php
Normal file
561
app/Http/Controllers/Api/AcnooSaleController.php
Normal file
@@ -0,0 +1,561 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Events\MultiPaymentProcessed;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\Product;
|
||||
use App\Models\Sale;
|
||||
use App\Models\Party;
|
||||
use App\Models\Stock;
|
||||
use App\Events\SaleSms;
|
||||
use App\Models\SaleDetails;
|
||||
use App\Helpers\HasUploader;
|
||||
use App\Models\Transaction;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class AcnooSaleController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
Use DateFilterTrait;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
// Build the query with all eager loads
|
||||
$query = Sale::with([
|
||||
'user:id,name,role',
|
||||
'party:id,name,email,phone,type,address',
|
||||
'details',
|
||||
'details.stock:id,batch_no,productStock',
|
||||
'details.product:id,productName,category_id,productCode,productPurchasePrice,productStock,product_type',
|
||||
'details.product.category:id,categoryName',
|
||||
'saleReturns.details',
|
||||
'vat:id,name,rate',
|
||||
'branch:id,name,phone,address',
|
||||
'transactions:id,platform,transaction_type,amount,date,invoice_no,reference_id,payment_type_id,meta',
|
||||
'transactions.paymentType:id,name,meta'
|
||||
])->where('business_id', $business_id);
|
||||
|
||||
// Filter returned sales
|
||||
$query->when(request('returned-sales') == "true", function ($query) {
|
||||
$query->whereHas('saleReturns');
|
||||
});
|
||||
|
||||
// Branch filter
|
||||
if ($request->filled('branch_id')) {
|
||||
$query->where('branch_id', $request->branch_id);
|
||||
}
|
||||
|
||||
// Apply date filter
|
||||
if(request('duration')){
|
||||
$this->applyDateFilter($query, request('duration'), 'saleDate', request('from_date'), request('to_date'));
|
||||
}
|
||||
|
||||
// Search filter
|
||||
if ($request->filled('search')) {
|
||||
$query->where(function ($q) use ($request) {
|
||||
$q->where('invoiceNumber', 'like', "%{$request->search}%")
|
||||
->orWhere('paymentType', 'like', "%{$request->search}%")
|
||||
->orWhereHas('party', fn($q) => $q->where('name', 'like', "%{$request->search}%"))
|
||||
->orWhereHas('payment_type', fn($q) => $q->where('name', 'like', "%{$request->search}%"))
|
||||
->orWhereHas('branch', fn($q) => $q->where('name', 'like', "%{$request->search}%"));
|
||||
});
|
||||
}
|
||||
|
||||
$data = $query->latest()->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'total_amount' => $data->sum('totalAmount'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function show(string $id)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$sale = Sale::with(['user:id,name,role', 'party:id,name,email,phone,type,address', 'details', 'details.stock:id,batch_no,productStock', 'details.product:id,productName,category_id,productCode,productPurchasePrice,productStock,product_type', 'details.product.category:id,categoryName', 'saleReturns.details', 'vat:id,name,rate', 'branch:id,name,phone,address', 'transactions:id,platform,transaction_type,amount,date,invoice_no,reference_id,payment_type_id,meta', 'transactions.paymentType:id,name,meta'])
|
||||
->where('business_id', $business_id)
|
||||
->where('id', $id)
|
||||
->first();
|
||||
|
||||
if (!$sale) {
|
||||
return response()->json([
|
||||
'message' => __('Sale not found.'),
|
||||
], 404);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Sale fetched successfully.'),
|
||||
'data' => $sale,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'party_id' => 'nullable|exists:parties,id',
|
||||
'vat_id' => 'nullable|exists:vats,id',
|
||||
'products' => 'required',
|
||||
'saleDate' => 'nullable|date',
|
||||
'image' => 'nullable|image|mimes:jpeg,png,jpg,gif,svg',
|
||||
'rounding_option' => 'nullable|in:none,round_up,nearest_whole_number,nearest_0.05,nearest_0.1,nearest_0.5',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$business_id = auth()->user()->business_id;
|
||||
$request_products = json_decode($request->products, true);
|
||||
$payments = json_decode($request->payments, true);
|
||||
|
||||
$paidAmount = collect($payments)
|
||||
->reject(fn($p) => strtolower($p['type'] ?? '') === 'cheque')
|
||||
->sum(fn($p) => $p['amount'] ?? 0);
|
||||
|
||||
if ($request->dueAmount > 0) {
|
||||
$allowDueForGuest = product_setting()?->modules['allow_due_sale'] ?? false;
|
||||
|
||||
// No party
|
||||
if (!$request->party_id) {
|
||||
if (!$allowDueForGuest) {
|
||||
return response()->json([
|
||||
'message' => __('You have not allowed guest sales, so you cannot sell on due for a walking customer.')
|
||||
], 400);
|
||||
}
|
||||
} else {
|
||||
// Party exist
|
||||
$party = Party::findOrFail($request->party_id);
|
||||
$newDue = $party->due + $request->dueAmount;
|
||||
|
||||
// Check credit limit
|
||||
if ($party->credit_limit > 0 && $newDue > $party->credit_limit) {
|
||||
return response()->json([
|
||||
'message' => __('Sale cannot be created. Party due will exceed credit limit!')
|
||||
], 400);
|
||||
}
|
||||
|
||||
$party->update(['due' => $newDue]);
|
||||
}
|
||||
}
|
||||
|
||||
updateBalance($paidAmount, 'increment');
|
||||
|
||||
$sale = Sale::create($request->except('image', 'isPaid', 'lossProfit', 'payment_type_id') + [
|
||||
'user_id' => auth()->id(),
|
||||
'business_id' => $business_id,
|
||||
'isPaid' => filter_var($request->isPaid, FILTER_VALIDATE_BOOLEAN) ? 1 : 0,
|
||||
'image' => $request->image ? $this->upload($request, 'image') : null,
|
||||
'meta' => [
|
||||
'note' => $request->note,
|
||||
],
|
||||
]);
|
||||
|
||||
$subtotal = 0;
|
||||
$totalPurchaseAmount = 0;
|
||||
|
||||
foreach ($request_products as $productData) {
|
||||
$productDiscount = $productData['discount'] ?? 0;
|
||||
|
||||
$product = Product::findOrFail($productData['product_id']);
|
||||
$qty = $productData['quantities'] ?? 1;
|
||||
$price = $productData['price'] ?? 0;
|
||||
|
||||
$lineSubtotal = ($price * $qty) - $productDiscount;
|
||||
$subtotal += $lineSubtotal;
|
||||
|
||||
// Combo Products
|
||||
if ($product->product_type == 'combo') {
|
||||
$comboTotalPurchase = 0;
|
||||
|
||||
foreach ($product->combo_products as $comboItem) {
|
||||
$stock = Stock::findOrFail($comboItem->stock_id);
|
||||
$requiredQty = $comboItem->quantity * $qty;
|
||||
|
||||
if ($stock->productStock < $requiredQty) {
|
||||
return response()->json([
|
||||
'message' => "Combo item '{$productData['product_name']}' (Batch: {$stock->batch_no}) not available. Available stock: {$stock->productStock}"
|
||||
], 400);
|
||||
}
|
||||
|
||||
// Decrement stock
|
||||
$stock->decrement('productStock', $requiredQty);
|
||||
|
||||
// Combo purchase total
|
||||
$comboTotalPurchase += $stock->productPurchasePrice * $requiredQty;
|
||||
}
|
||||
|
||||
$totalPurchaseAmount += $comboTotalPurchase;
|
||||
|
||||
// Store combo in SaleDetails
|
||||
$saleDetails[] = [
|
||||
'sale_id' => $sale->id,
|
||||
'stock_id' => null,
|
||||
'product_id' => $product->id,
|
||||
'price' => $price,
|
||||
'discount' => $productDiscount,
|
||||
'lossProfit' => $lineSubtotal - $comboTotalPurchase,
|
||||
'quantities' => $qty,
|
||||
'productPurchasePrice' => $comboTotalPurchase ?? 0,
|
||||
'expire_date' => null,
|
||||
'warranty_guarantee_info' => $product->warranty_guarantee_info
|
||||
? json_encode($product->warranty_guarantee_info)
|
||||
: null,
|
||||
];
|
||||
} // Single / Variant Products
|
||||
else {
|
||||
$stock = Stock::findOrFail($productData['stock_id']);
|
||||
|
||||
if ($stock->productStock < $qty) {
|
||||
return response()->json([
|
||||
'message' => "Stock not available for product: {$productData['product_name']}. Available: {$stock->productStock}"
|
||||
], 400);
|
||||
}
|
||||
|
||||
// Decrement stock
|
||||
$stock->decrement('productStock', $qty);
|
||||
$purchasePrice = $stock->productPurchasePrice ?? 0;
|
||||
|
||||
// Calculate profit/loss
|
||||
$totalPurchaseAmount += ($purchasePrice * $qty);
|
||||
|
||||
$saleDetails[] = [
|
||||
'sale_id' => $sale->id,
|
||||
'stock_id' => $stock->id,
|
||||
'product_id' => $product->id,
|
||||
'price' => $price,
|
||||
'discount' => $productDiscount,
|
||||
'lossProfit' => $lineSubtotal - ($purchasePrice * $qty),
|
||||
'quantities' => $qty,
|
||||
'productPurchasePrice' => $purchasePrice,
|
||||
'expire_date' => $stock->expire_date ?? null,
|
||||
'warranty_guarantee_info' => $product->warranty_guarantee_info
|
||||
? json_encode($product->warranty_guarantee_info)
|
||||
: null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
SaleDetails::insert($saleDetails);
|
||||
|
||||
$saleLossProfit = ($subtotal - $totalPurchaseAmount) - ($request->discountAmount ?? 0);
|
||||
|
||||
$sale->update([
|
||||
'lossProfit' => $saleLossProfit,
|
||||
]);
|
||||
|
||||
// MultiPaymentProcessed Event
|
||||
event(new MultiPaymentProcessed(
|
||||
$payments,
|
||||
$sale->id,
|
||||
'sale',
|
||||
$paidAmount,
|
||||
$request->party_id ?? null
|
||||
));
|
||||
|
||||
// Send SMS
|
||||
event(new SaleSms($sale));
|
||||
|
||||
DB::commit();
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $sale->load('user:id,name,role', 'party:id,name,email,phone,type,address', 'details', 'details.stock:id,batch_no', 'details.product:id,productName,category_id,product_type', 'details.product.category:id,categoryName', 'saleReturns.details', 'vat:id,name,rate', 'payment_type:id,name', 'branch:id,name,phone,address'),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json(['message' => $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$request->validate([
|
||||
'party_id' => 'nullable|exists:parties,id',
|
||||
'vat_id' => 'nullable|exists:vats,id',
|
||||
'products' => 'required',
|
||||
'saleDate' => 'nullable|date',
|
||||
'image' => 'nullable|image|mimes:jpeg,png,jpg,gif,svg',
|
||||
'rounding_option' => 'nullable|in:none,round_up,nearest_whole_number,nearest_0.05,nearest_0.1,nearest_0.5',
|
||||
]);
|
||||
|
||||
$sale = Sale::findOrFail($id);
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
if ($sale->load('saleReturns')->saleReturns->count() > 0) {
|
||||
return response()->json([
|
||||
'message' => __("You cannot update this sale because it has already been returned.")
|
||||
], 400);
|
||||
}
|
||||
|
||||
$request_products = json_decode($request->products, true);
|
||||
$payments = json_decode($request->payments, true);
|
||||
$prevDetails = SaleDetails::where('sale_id', $sale->id)->get();
|
||||
|
||||
// Rollback previous stock
|
||||
foreach ($prevDetails as $prevItem) {
|
||||
if ($prevItem->stock_id) {
|
||||
$stock = Stock::findOrFail($prevItem->stock_id);
|
||||
$stock->increment('productStock', $prevItem->quantities);
|
||||
}
|
||||
}
|
||||
|
||||
$prevDetails->each->delete();
|
||||
|
||||
$saleDetails = [];
|
||||
$totalLossProfit = 0;
|
||||
$totalProductWiseDiscount = 0;
|
||||
|
||||
foreach ($request_products as $productData) {
|
||||
$product = Product::findOrFail($productData['product_id']);
|
||||
$qty = $productData['quantities'] ?? 1;
|
||||
$price = $productData['price'] ?? 0;
|
||||
|
||||
$productDiscount = $productData['discount'] ?? 0;
|
||||
$totalProductWiseDiscount += $productDiscount;
|
||||
|
||||
$unitSalePrice = $price;
|
||||
$unitDiscount = $productDiscount / max($qty, 1);
|
||||
$finalSalePricePerUnit = $unitSalePrice - $unitDiscount;
|
||||
|
||||
// Combo product
|
||||
if ($product->product_type == 'combo') {
|
||||
foreach ($product->combo_products as $comboItem) {
|
||||
$stock = Stock::findOrFail($comboItem->stock_id);
|
||||
$requiredQty = $comboItem->quantity * $qty;
|
||||
|
||||
if ($stock->productStock < $requiredQty) {
|
||||
return response()->json([
|
||||
'message' => "Combo item '{$productData['product_name']}' (Batch: {$stock->batch_no}) not available. Available stock: {$stock->productStock}"
|
||||
], 400);
|
||||
}
|
||||
|
||||
// Decrement stock
|
||||
$stock->decrement('productStock', $requiredQty);
|
||||
|
||||
// Total combo purchase
|
||||
$comboPurchaseTotal += ($stock->productPurchasePrice * $requiredQty); // 🔥 changed
|
||||
}
|
||||
|
||||
// purchase price per unit of combo
|
||||
$purchaseUnit = $comboPurchaseTotal / max($qty, 1);
|
||||
|
||||
// correct lossProfit
|
||||
$lossProfit = ($finalSalePricePerUnit - $purchaseUnit) * $qty;
|
||||
$totalLossProfit += $lossProfit;
|
||||
|
||||
$saleDetails[] = [
|
||||
'sale_id' => $sale->id,
|
||||
'stock_id' => null,
|
||||
'product_id' => $product->id,
|
||||
'price' => $price,
|
||||
'discount' => $productDiscount,
|
||||
'lossProfit' => $lossProfit,
|
||||
'quantities' => $qty,
|
||||
'productPurchasePrice' => $purchaseUnit,
|
||||
'expire_date' => null,
|
||||
'warranty_guarantee_info' => $product->warranty_guarantee_info
|
||||
? json_encode($product->warranty_guarantee_info)
|
||||
: null,
|
||||
];
|
||||
} // Single / Variant product
|
||||
else {
|
||||
$stock = Stock::findOrFail($productData['stock_id']);
|
||||
if ($stock->productStock < $qty) {
|
||||
return response()->json([
|
||||
'message' => "Stock not available for product: {$productData['product_name']}. Available: {$stock->productStock}"
|
||||
], 400);
|
||||
}
|
||||
|
||||
$stock->decrement('productStock', $qty);
|
||||
|
||||
$purchaseUnit = $stock->productPurchasePrice ?? 0;
|
||||
$lossProfit = ($finalSalePricePerUnit - $purchaseUnit) * $qty;
|
||||
$totalLossProfit += $lossProfit;
|
||||
|
||||
$saleDetails[] = [
|
||||
'sale_id' => $sale->id,
|
||||
'stock_id' => $stock->id,
|
||||
'product_id' => $product->id,
|
||||
'price' => $price,
|
||||
'discount' => $productDiscount,
|
||||
'lossProfit' => $lossProfit,
|
||||
'quantities' => $qty,
|
||||
'productPurchasePrice' => $purchaseUnit,
|
||||
'expire_date' => $stock->expire_date ?? null,
|
||||
'warranty_guarantee_info' => $product->warranty_guarantee_info ? json_encode($product->warranty_guarantee_info) : null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
SaleDetails::insert($saleDetails);
|
||||
|
||||
// Check if any old transaction type = deposit
|
||||
$hasDeposit = Transaction::where('business_id', $business_id)
|
||||
->where('reference_id', $sale->id)
|
||||
->where('platform', 'sale')
|
||||
->where('type', 'deposit')
|
||||
->exists();
|
||||
|
||||
$paidAmount = collect($payments)
|
||||
->reject(function ($p) use ($hasDeposit) {
|
||||
// exclude cheque only if not deposit
|
||||
return !$hasDeposit && strtolower($p['type'] ?? '') === 'cheque';
|
||||
})
|
||||
->sum(fn($p) => $p['amount'] ?? 0);
|
||||
|
||||
$dueAmount = max($request->totalAmount - $paidAmount, 0);
|
||||
|
||||
|
||||
// Handle party due
|
||||
if ($sale->dueAmount || $dueAmount) {
|
||||
$party = Party::findOrFail($request->party_id);
|
||||
|
||||
$newDue = $request->party_id == $sale->party_id
|
||||
? (($party->due - $sale->dueAmount) + $dueAmount)
|
||||
: ($party->due + $dueAmount);
|
||||
|
||||
if ($party->credit_limit > 0 && $newDue > $party->credit_limit) {
|
||||
return response()->json([
|
||||
'message' => __("Cannot update sale. Party due will exceed credit limit!")
|
||||
], 400);
|
||||
}
|
||||
|
||||
$party->update(['due' => $newDue]);
|
||||
|
||||
if ($request->party_id != $sale->party_id) {
|
||||
$prev_party = Party::findOrFail($sale->party_id);
|
||||
$prev_party->update([
|
||||
'due' => $prev_party->due - $sale->dueAmount
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust business balance
|
||||
$balanceDiff = $paidAmount - $sale->paidAmount;
|
||||
updateBalance($balanceDiff, 'increment');
|
||||
|
||||
$sale->update($request->except('image', 'isPaid', 'paidAmount', 'paidAmount', 'dueAmount') + [
|
||||
'user_id' => auth()->id(),
|
||||
'isPaid' => filter_var($request->isPaid, FILTER_VALIDATE_BOOLEAN) ? 1 : 0,
|
||||
'lossProfit' => $totalLossProfit - ($request->discountAmount ?? 0) - $totalProductWiseDiscount,
|
||||
'image' => $request->image ? $this->upload($request, 'image', $sale->image) : $sale->image,
|
||||
'paidAmount' => $paidAmount > $request->totalAmount ? $request->totalAmount : $paidAmount,
|
||||
'dueAmount' => $dueAmount,
|
||||
'meta' => [
|
||||
'note' => $request->note,
|
||||
],
|
||||
]);
|
||||
|
||||
// Multiple Payment Process
|
||||
$oldTransactions = Transaction::where('business_id', $business_id)
|
||||
->where('reference_id', $sale->id)
|
||||
->where('platform', 'sale')
|
||||
->get();
|
||||
|
||||
// Revert old transactions
|
||||
foreach ($oldTransactions as $old) {
|
||||
switch ($old->transaction_type) {
|
||||
case 'bank_payment':
|
||||
$paymentType = PaymentType::find($old->payment_type_id);
|
||||
if ($paymentType) {
|
||||
$paymentType->decrement('balance', $old->amount);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'wallet_payment':
|
||||
if ($request->party_id) {
|
||||
$party = Party::find($request->party_id);
|
||||
if ($party) {
|
||||
$party->increment('wallet', $old->amount);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'cash_payment':
|
||||
case 'cheque_payment':
|
||||
// nothing to revert for cash/cheque
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete old transactions
|
||||
Transaction::where('business_id', $business_id)
|
||||
->where('reference_id', $sale->id)
|
||||
->where('platform', 'sale')
|
||||
->delete();
|
||||
|
||||
// Process new payments
|
||||
event(new MultiPaymentProcessed(
|
||||
$payments ?? [],
|
||||
$sale->id,
|
||||
'sale',
|
||||
$paidAmount,
|
||||
$request->party_id ?? null,
|
||||
));
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Sale updated successfully.'),
|
||||
'data' => $sale->load(
|
||||
'details',
|
||||
'details.product:id,productName,product_type',
|
||||
'details.stock:id,batch_no',
|
||||
'party:id,name,email,phone,address',
|
||||
'vat:id,name,rate',
|
||||
'branch:id,name,phone,address'
|
||||
),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json([
|
||||
'message' => 'Something went wrong.',
|
||||
'error' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(Sale $sale)
|
||||
{
|
||||
foreach ($sale->details as $item) {
|
||||
Stock::findOrFail($item->stock_id)->increment('productStock', $item->quantities);
|
||||
}
|
||||
|
||||
if ($sale->dueAmount) {
|
||||
$party = Party::findOrFail($sale->party_id);
|
||||
$party->update([
|
||||
'due' => $party->due - $sale->dueAmount
|
||||
]);
|
||||
}
|
||||
|
||||
updateBalance($sale->paidAmount, 'decrement');
|
||||
|
||||
if (file_exists($sale->image)) {
|
||||
Storage::delete($sale->image);
|
||||
}
|
||||
|
||||
$sale->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data deleted successfully.'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
18
app/Http/Controllers/Api/AcnooSubscribesController.php
Normal file
18
app/Http/Controllers/Api/AcnooSubscribesController.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\PlanSubscribe;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AcnooSubscribesController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$subscribes = PlanSubscribe::where('user_id', auth()->id())->latest()->get();
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $subscribes
|
||||
]);
|
||||
}
|
||||
}
|
||||
18
app/Http/Controllers/Api/AcnooSubscriptionsController.php
Normal file
18
app/Http/Controllers/Api/AcnooSubscriptionsController.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Plan;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AcnooSubscriptionsController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$plans = Plan::whereStatus(1)->latest()->get();
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $plans,
|
||||
]);
|
||||
}
|
||||
}
|
||||
18
app/Http/Controllers/Api/AcnooTermsController.php
Normal file
18
app/Http/Controllers/Api/AcnooTermsController.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Option;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AcnooTermsController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$term = Option::where('key', 'term')->first()->value;
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $term ?? 'Terms & Conditions.',
|
||||
]);
|
||||
}
|
||||
}
|
||||
103
app/Http/Controllers/Api/AcnooUserController.php
Normal file
103
app/Http/Controllers/Api/AcnooUserController.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class AcnooUserController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
$data = User::with('branch:id,name')
|
||||
->where('business_id', $user->business_id)
|
||||
->when($user->role == 'staff', function ($q) use ($user) {
|
||||
$q->where('branch_id', $user->branch_id);
|
||||
})
|
||||
->when($user->branch_id || $user->active_branch_id, function ($q) use ($user) {
|
||||
$q->where('branch_id', $user->branch_id ?? $user->active_branch_id);
|
||||
})
|
||||
->where('id', '!=', auth()->id())
|
||||
->where('role', 'staff')
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|max:30',
|
||||
'password' => 'required|min:4|max:15',
|
||||
'email' => 'required|email|unique:users,email',
|
||||
'branch_id' => 'nullable|exists:branches,id',
|
||||
]);
|
||||
|
||||
$data = User::create([
|
||||
'role' => 'staff',
|
||||
'name' => $request->name,
|
||||
'email' => $request->email,
|
||||
'visibility' => $request->visibility,
|
||||
'password' => Hash::make($request->password),
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'branch_id' => $request->branch_id ?? auth()->user()->branch_id ?? auth()->user()->active_branch_id,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, User $user)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|max:30',
|
||||
'password' => 'nullable|min:4|max:15',
|
||||
'branch_id' => 'nullable|exists:branches,id',
|
||||
'email' => 'required|email|unique:users,email,' . $user->id,
|
||||
]);
|
||||
|
||||
$user->update([
|
||||
'name' => $request->name,
|
||||
'email' => $request->email,
|
||||
'branch_id' => $request->branch_id,
|
||||
'visibility' => $request->visibility,
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'password' => $request->password ? Hash::make($request->password) : $user->password,
|
||||
'branch_id' => $request->branch_id ?? auth()->user()->branch_id ?? auth()->user()->active_branch_id,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.')
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(User $user)
|
||||
{
|
||||
$user->delete();
|
||||
return response()->json([
|
||||
'message' => __('Data deleted successfully.'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
162
app/Http/Controllers/Api/AcnooVatController.php
Normal file
162
app/Http/Controllers/Api/AcnooVatController.php
Normal file
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Business;
|
||||
use App\Models\Vat;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AcnooVatController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$vats = Vat::where('business_id', auth()->user()->business_id)
|
||||
->when(request('type') == 'single', function ($query) {
|
||||
$query->whereNull('sub_vat');
|
||||
})
|
||||
->when(request('type') == 'group', function ($query) {
|
||||
$query->whereNotNull('sub_vat');
|
||||
})
|
||||
->when(request('status'), function ($query) {
|
||||
$query->where('status', request('status') == 'active' ? 1 : 0);
|
||||
})
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Data fetched successfully.',
|
||||
'data' => $vats,
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'vat_ids' => 'required_if:rate,null',
|
||||
'rate' => 'required_if:rate,null|numeric',
|
||||
]);
|
||||
|
||||
if ($request->rate && !$request->vat_ids) {
|
||||
|
||||
$vat = Vat::create($request->all() + [
|
||||
'business_id' => auth()->user()->business_id,
|
||||
]);
|
||||
|
||||
} elseif (!$request->rate && $request->vat_ids) {
|
||||
|
||||
$vats = Vat::whereIn('id', $request->vat_ids)->select('id', 'name', 'rate')->get();
|
||||
|
||||
$tax_rate = 0;
|
||||
$sub_vats = [];
|
||||
|
||||
foreach ($vats as $vat) {
|
||||
$sub_vats[] = [
|
||||
'id' => $vat->id,
|
||||
'name' => $vat->name,
|
||||
'rate' => $vat->rate,
|
||||
];
|
||||
$tax_rate += $vat->rate;
|
||||
}
|
||||
|
||||
$vat = Vat::create([
|
||||
'rate' => $tax_rate,
|
||||
'sub_vat' => $sub_vats,
|
||||
'name' => $request->name,
|
||||
'business_id' => auth()->user()->business_id,
|
||||
]);
|
||||
|
||||
} else {
|
||||
return response()->json([
|
||||
'message' => 'Invalid data format.',
|
||||
], 406);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Data created successfully.',
|
||||
'data' => $vat,
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request, Vat $vat)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'vat_ids' => 'required_if:rate,null',
|
||||
'rate' => 'required_if:rate,null|numeric',
|
||||
]);
|
||||
|
||||
if ($request->rate && !$request->vat_ids) {
|
||||
|
||||
$vat->update($request->all());
|
||||
|
||||
$vatGroupExist = Vat::where('sub_vat', 'LIKE', '%"id":' . $vat->id . '%')->get();
|
||||
foreach ($vatGroupExist as $group) {
|
||||
$subVats = collect($group->sub_vat)->map(function ($subVat) use ($vat) {
|
||||
if ($subVat['id'] == $vat->id) {
|
||||
$subVat['rate'] = $vat->rate;
|
||||
$subVat['name'] = $vat->name;
|
||||
}
|
||||
return $subVat;
|
||||
});
|
||||
|
||||
$group->update([
|
||||
'rate' => $subVats->sum('rate'),
|
||||
'sub_vat' => $subVats->toArray(),
|
||||
]);
|
||||
}
|
||||
|
||||
} elseif (!$request->rate && $request->vat_ids) {
|
||||
|
||||
$vats = Vat::whereIn('id', $request->vat_ids)->select('id', 'name', 'rate')->get();
|
||||
|
||||
$tax_rate = 0;
|
||||
$sub_vats = [];
|
||||
|
||||
foreach ($vats as $single_tax) {
|
||||
$sub_vats[] = [
|
||||
'id' => $single_tax->id,
|
||||
'name' => $single_tax->name,
|
||||
'rate' => $single_tax->rate,
|
||||
];
|
||||
$tax_rate += $single_tax->rate;
|
||||
}
|
||||
|
||||
$vat->update([
|
||||
'rate' => $tax_rate,
|
||||
'sub_vat' => $sub_vats,
|
||||
'name' => $request->name,
|
||||
'status' => $request->status ?? $vat->status,
|
||||
]);
|
||||
|
||||
} else {
|
||||
return response()->json([
|
||||
'message' => 'Invalid data format.',
|
||||
], 406);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Data updated successfully.',
|
||||
'data' => $vat,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function destroy(Vat $vat)
|
||||
{
|
||||
// When sub_vat is null, check if the VAT exists in any other VAT's sub_vat
|
||||
if (is_null($vat->sub_vat) && Vat::where('sub_vat', 'LIKE', '%"id":' . $vat->id . '%')->exists()) {
|
||||
return response()->json([
|
||||
'message' => 'Cannot delete. This VAT is part of a VAT group.',
|
||||
], 404);
|
||||
}
|
||||
|
||||
$vat->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Data deleted successfully',
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Auth;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Mail\PasswordReset;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class AcnooForgotPasswordController extends Controller
|
||||
{
|
||||
public function sendResetCode(Request $request) : JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'email' => 'required|email|exists:users,email'
|
||||
]);
|
||||
|
||||
$expire = now()->addHour();
|
||||
$code = random_int(100000,999999);
|
||||
$user = User::where('email',$request->email)->first();
|
||||
$user->update(['remember_token' => $code, 'email_verified_at' => $expire]);
|
||||
|
||||
$data = [
|
||||
'code' => $code
|
||||
];
|
||||
|
||||
try {
|
||||
if (env('QUEUE_MAIL')) {
|
||||
Mail::to($request->email)->queue(new PasswordReset($data));
|
||||
} else {
|
||||
Mail::to($request->email)->send(new PasswordReset($data));
|
||||
}
|
||||
return response()->json([
|
||||
'message' => 'Password reset code has been sent to your email.',
|
||||
]);
|
||||
|
||||
} catch (\Exception $exception){
|
||||
return response()->json([
|
||||
'message' => $exception->getMessage(),
|
||||
], 422);
|
||||
}
|
||||
}
|
||||
|
||||
public function verifyResetCode(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'code' => 'required|integer',
|
||||
'email' => 'required|exists:users,email',
|
||||
]);
|
||||
|
||||
$user = User::where('email', $request->email)->first();
|
||||
|
||||
if ($user->remember_token == $request->code) {
|
||||
if ($user->email_verified_at > now()) {
|
||||
return response()->json([
|
||||
'message' => __('The code has been verified.')
|
||||
]);
|
||||
} else {
|
||||
return response()->json([
|
||||
'error' => __('The verification code has expired.')
|
||||
], 400);
|
||||
}
|
||||
} else {
|
||||
return response()->json([
|
||||
'error' => __('Invalid Code.')
|
||||
], 404);
|
||||
}
|
||||
}
|
||||
|
||||
public function resetPassword(Request $request) : JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'email' => 'required|exists:users,email',
|
||||
'password' => ['required', 'min:4'],
|
||||
]);
|
||||
|
||||
$user = User::where('email', $request->email)->first();
|
||||
|
||||
$user->update([
|
||||
'password' => bcrypt($request->password),
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Your password has been changed!',
|
||||
]);
|
||||
}
|
||||
}
|
||||
323
app/Http/Controllers/Api/Auth/AuthController.php
Normal file
323
app/Http/Controllers/Api/Auth/AuthController.php
Normal file
@@ -0,0 +1,323 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Auth;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Branch;
|
||||
use App\Models\Currency;
|
||||
use App\Mail\WelcomeMail;
|
||||
use App\Models\UserCurrency;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Sanctum\NewAccessToken;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use App\Http\Controllers\Auth\RegisteredUserController;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
public function otpSettings()
|
||||
{
|
||||
$otp_settings = get_option('email-varification');
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Data fetched successfully.',
|
||||
'data' => $otp_settings
|
||||
]);
|
||||
}
|
||||
|
||||
public function signUp(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'password' => 'required|min:6|max:100',
|
||||
'email' => 'required|email',
|
||||
]);
|
||||
|
||||
$code = random_int(100000, 999999);
|
||||
$otpController = new RegisteredUserController();
|
||||
$visibility_time = $otpController->getOtpTimeInSeconds();
|
||||
$expire = now()->addSeconds($visibility_time);
|
||||
|
||||
$data = [
|
||||
'code' => $code,
|
||||
'name' => $request->name,
|
||||
];
|
||||
|
||||
$user = User::where('email', $request->email)->first();
|
||||
if ($user && $user->business_id) {
|
||||
return response()->json([
|
||||
'message' => 'This email is already exists.',
|
||||
], 406);
|
||||
}
|
||||
|
||||
$otp_settings = get_option('email-varification');
|
||||
$verify_email = ($otp_settings['otp_status'] ?? false) && $otp_settings['otp_status'] == 'on' ? 1 : 0;
|
||||
|
||||
if ($verify_email) {
|
||||
if (env('MAIL_USERNAME')) {
|
||||
if (env('QUEUE_MAIL')) {
|
||||
Mail::to($request->email)->queue(new WelcomeMail($data));
|
||||
} else {
|
||||
Mail::to($request->email)->send(new WelcomeMail($data));
|
||||
}
|
||||
} else {
|
||||
return response()->json([
|
||||
'message' => __('Mail service is not configured. Please contact your administrator.'),
|
||||
], 406);
|
||||
}
|
||||
}
|
||||
|
||||
$user = User::updateOrCreate(['email' => $request->email], $request->except('password') + [
|
||||
'is_verified' => $verify_email ? 0 : 1,
|
||||
'remember_token' => $verify_email ? $code : NULL,
|
||||
'email_verified_at' => $verify_email ? $expire : NULL,
|
||||
'password' => Hash::make($request->password),
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => $verify_email ? 'An otp code has been sent to your email. Please check and confirm.' : 'Sign Up completed. Please setup your profile.',
|
||||
'token' => $verify_email ? null : $user->createToken('createToken')->plainTextToken,
|
||||
'data' => $user,
|
||||
]);
|
||||
}
|
||||
|
||||
public function submitOtp(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'email' => 'required|email',
|
||||
'otp' => 'required|min:4|max:15',
|
||||
]);
|
||||
|
||||
$user = User::where('email', $request->email)->first();
|
||||
|
||||
if (!$user) {
|
||||
return response()->json([
|
||||
'status' => 404,
|
||||
'message' => __('User not found'),
|
||||
], 404);
|
||||
}
|
||||
|
||||
if ($user->remember_token == $request->otp) {
|
||||
if ($user->email_verified_at > now()) {
|
||||
|
||||
Auth::login($user);
|
||||
$is_setup = $user->business_id ? true : false;
|
||||
$token = $user->createToken('createToken')->plainTextToken;
|
||||
$accessToken = $user->createToken('createToken');
|
||||
$this->setAccessTokenExpiration($accessToken);
|
||||
|
||||
$user->update([
|
||||
'is_verified' => 1,
|
||||
'remember_token' => NULL,
|
||||
'email_verified_at' => now(),
|
||||
]);
|
||||
|
||||
$currency = Currency::select('id', 'name', 'code', 'symbol', 'position')->where('is_default', 1)->first();
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Logged In successfully!',
|
||||
'is_setup' => $is_setup,
|
||||
'token' => $token,
|
||||
'currency' => $currency,
|
||||
]);
|
||||
} else {
|
||||
return response()->json([
|
||||
'error' => __('The verification otp has been expired.')
|
||||
], 400);
|
||||
}
|
||||
} else {
|
||||
return response()->json([
|
||||
'error' => __('Invalid otp.')
|
||||
], 404);
|
||||
}
|
||||
}
|
||||
|
||||
public function login(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'password' => 'required',
|
||||
'email' => 'required|email',
|
||||
]);
|
||||
|
||||
if (auth()->attempt($request->only('email', 'password'))) {
|
||||
$user = auth()->user();
|
||||
|
||||
$business = $user->business;
|
||||
$branch = Branch::find($user->branch_id);
|
||||
|
||||
if (multibranch_active() && branch_count()) {
|
||||
if ($branch && !$branch->status && $user->branch_id && !$branch->is_main) {
|
||||
|
||||
Auth::logout();
|
||||
return response()->json([
|
||||
'message' => 'This branch is not active, Please contact with manager.',
|
||||
], 406);
|
||||
}
|
||||
} elseif (!multibranch_active()) {
|
||||
if ($user->active_branch_id) {
|
||||
$user->update([
|
||||
'active_branch_id' => NULL
|
||||
]);
|
||||
} elseif ($user->branch_id && !$branch->is_main) {
|
||||
|
||||
Auth::logout();
|
||||
return response()->json([
|
||||
'message' => 'Multibranch is not allowed in your current package, please upgrade your subscription plan.',
|
||||
], 406);
|
||||
}
|
||||
} elseif (!$branch && $user->branch_id) {
|
||||
Auth::logout();
|
||||
return response()->json([
|
||||
'message' => 'Your current branch has been deleted, Please contact with manager.',
|
||||
], 406);
|
||||
} elseif ($business && !$business->status) {
|
||||
Auth::logout();
|
||||
return response()->json([
|
||||
'message' => 'Your business is inactive. Please contact your administrator.',
|
||||
], 406);
|
||||
}
|
||||
|
||||
if ($user->role != 'staff' && $user->role != 'shop-owner') {
|
||||
return response()->json([
|
||||
'message' => 'You can not login as ' . $user->role . ' from the app!'
|
||||
], 406);
|
||||
}
|
||||
|
||||
if ($user->remember_token && !$user->business_id) { // If user didn't verify email
|
||||
|
||||
$code = random_int(100000, 999999);
|
||||
$expire = now()->addMinutes(env('OTP_VISIBILITY_TIME') ?? 3);
|
||||
$data = [
|
||||
'code' => $code,
|
||||
'name' => $request->name,
|
||||
];
|
||||
|
||||
if (env('MAIL_USERNAME')) {
|
||||
if (env('QUEUE_MAIL')) {
|
||||
Mail::to($request->email)->queue(new WelcomeMail($data));
|
||||
} else {
|
||||
Mail::to($request->email)->send(new WelcomeMail($data));
|
||||
}
|
||||
} else {
|
||||
return response()->json([
|
||||
'message' => __('Mail service is not configured. Please contact your administrator.'),
|
||||
], 406);
|
||||
}
|
||||
|
||||
User::where('email', $request->email)->first()->update(['remember_token' => $code, 'email_verified_at' => $expire]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'An otp code has been sent to your email. Please check and confirm.',
|
||||
], 201);
|
||||
}
|
||||
|
||||
$currency = UserCurrency::select('id', 'name', 'code', 'symbol', 'position')->where('business_id', $user->business_id)->first();
|
||||
|
||||
return response()->json([
|
||||
'message' => 'User login successfully!',
|
||||
'data' => [
|
||||
'is_setup' => $user->business_id ? true : false,
|
||||
'token' => $user->createToken('createToken')->plainTextToken,
|
||||
'currency' => $currency ?? Currency::select('id', 'name', 'code', 'symbol', 'position')->where('is_default', 1)->first(),
|
||||
],
|
||||
]);
|
||||
} else {
|
||||
return response()->json([
|
||||
'message' => 'Invalid email or password!'
|
||||
], 404);
|
||||
}
|
||||
}
|
||||
|
||||
protected function setAccessTokenExpiration(NewAccessToken $accessToken)
|
||||
{
|
||||
$expiration = now()->addMinutes(Config::get('sanctum.expiration'));
|
||||
|
||||
DB::table('personal_access_tokens')
|
||||
->where('id', $accessToken->accessToken->id)
|
||||
->update(['expires_at' => $expiration]);
|
||||
}
|
||||
|
||||
public function signOut(): JsonResponse
|
||||
{
|
||||
$currentToken = auth()->user()->currentAccessToken();
|
||||
|
||||
if ($currentToken) {
|
||||
$currentToken->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Sign out successfully'),
|
||||
]);
|
||||
} else {
|
||||
return response()->json([
|
||||
'message' => __('Unauthorized'),
|
||||
], 401);
|
||||
}
|
||||
}
|
||||
|
||||
public function refreshToken()
|
||||
{
|
||||
if (auth()->user()->tokens()) {
|
||||
|
||||
auth()->user()->currentAccessToken()->delete();
|
||||
$data['token'] = auth()->user()->createToken('createToken')->plainTextToken;
|
||||
return response()->json($data);
|
||||
} else {
|
||||
return response()->json([
|
||||
'message' => __('Unauthorized'),
|
||||
], 401);
|
||||
}
|
||||
}
|
||||
|
||||
public function resendOtp(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'email' => 'required|email|exists:users,email',
|
||||
]);
|
||||
|
||||
$code = random_int(100000, 999999);
|
||||
$otpController = new RegisteredUserController();
|
||||
$visibility_time = $otpController->getOtpTimeInSeconds();
|
||||
$expire = now()->addSeconds($visibility_time);
|
||||
|
||||
$data = [
|
||||
'code' => $code,
|
||||
'name' => $request->name,
|
||||
];
|
||||
|
||||
if (env('MAIL_USERNAME')) {
|
||||
if (env('QUEUE_MAIL')) {
|
||||
Mail::to($request->email)->queue(new WelcomeMail($data));
|
||||
} else {
|
||||
Mail::to($request->email)->send(new WelcomeMail($data));
|
||||
}
|
||||
} else {
|
||||
return response()->json([
|
||||
'message' => __('Mail service is not configured. Please contact your administrator.'),
|
||||
], 406);
|
||||
}
|
||||
|
||||
User::where('email', $request->email)->first()->update(['remember_token' => $code, 'email_verified_at' => $expire]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'An otp code has been sent to your email. Please check and confirm.',
|
||||
]);
|
||||
}
|
||||
|
||||
public function moduleCheck()
|
||||
{
|
||||
if (moduleCheck(request('module_name'))) {
|
||||
return response()->json([
|
||||
'status' => true
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'status' => false
|
||||
]);
|
||||
}
|
||||
}
|
||||
168
app/Http/Controllers/Api/BankController.php
Normal file
168
app/Http/Controllers/Api/BankController.php
Normal file
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\PaymentType;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class BankController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$data = PaymentType::with('branch:id,name')->where('business_id', auth()->user()->business_id)->latest()->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'branch_id' => 'nullable|exists:branches,id',
|
||||
'opening_balance' => 'nullable|numeric|min:0',
|
||||
'opening_date' => 'nullable|date',
|
||||
'show_in_invoice' => 'boolean',
|
||||
'meta' => 'nullable|array',
|
||||
'meta.account_number' => 'nullable|string|max:255',
|
||||
'meta.routing_number' => 'nullable|string|max:255',
|
||||
'meta.upi_id' => 'nullable|string|max:255',
|
||||
'meta.bank_name' => 'nullable|string|max:255',
|
||||
'meta.account_holder' => 'nullable|string|max:255',
|
||||
'meta.branch' => 'nullable|string|max:255',
|
||||
]);
|
||||
|
||||
$forbidden = ['cash', 'cheque'];
|
||||
if (in_array(strtolower($request->name), $forbidden)) {
|
||||
return response()->json([
|
||||
'message' => __('You cannot create a bank account with this name.'),
|
||||
], 422);
|
||||
}
|
||||
|
||||
$data = PaymentType::create($request->except('business_id', 'show_in_invoice', 'balance', 'opening_balance', 'meta') + [
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'opening_balance' => $request->opening_balance ?? 0,
|
||||
'balance' => $request->opening_balance ?? 0,
|
||||
'show_in_invoice' => $request->show_in_invoice,
|
||||
'meta' => [
|
||||
'account_number' => $request->account_number,
|
||||
'routing_number' => $request->routing_number,
|
||||
'upi_id' => $request->upi_id,
|
||||
'bank_name' => $request->bank_name,
|
||||
'account_holder' => $request->account_holder,
|
||||
'branch' => $request->branch,
|
||||
]
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
{
|
||||
$data = PaymentType::with('branch:id,name')->where('business_id', auth()->user()->business_id)->find($id);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'branch_id' => 'nullable|exists:branches,id',
|
||||
'opening_balance' => 'nullable|numeric|min:0',
|
||||
'opening_date' => 'nullable|date',
|
||||
'show_in_invoice' => 'boolean',
|
||||
'meta' => 'nullable|array',
|
||||
'meta.account_number' => 'nullable|string|max:255',
|
||||
'meta.routing_number' => 'nullable|string|max:255',
|
||||
'meta.upi_id' => 'nullable|string|max:255',
|
||||
'meta.bank_name' => 'nullable|string|max:255',
|
||||
'meta.account_holder' => 'nullable|string|max:255',
|
||||
'meta.branch' => 'nullable|string|max:255',
|
||||
]);
|
||||
|
||||
$payment_type = PaymentType::findOrFail($id);
|
||||
|
||||
$forbidden = ['cash', 'cheque'];
|
||||
if (in_array(strtolower($request->name), $forbidden)) {
|
||||
return response()->json([
|
||||
'message' => __('You cannot create a bank account with this name.'),
|
||||
], 422);
|
||||
}
|
||||
|
||||
$hasTransactions = $payment_type->transactions()->exists();
|
||||
|
||||
if ($hasTransactions) {
|
||||
return response()->json([
|
||||
'message' => __("You can't Change opening balance because this bank already has transactions.")
|
||||
], 422);
|
||||
}
|
||||
|
||||
$updateData = $request->except('business_id', 'show_in_invoice', 'balance', 'opening_balance', 'meta');
|
||||
|
||||
// Add controlled fields
|
||||
$updateData['business_id'] = auth()->user()->business_id;
|
||||
$updateData['show_in_invoice'] = $request->show_in_invoice;
|
||||
|
||||
// Only update balances if no transactions exist
|
||||
if (!$hasTransactions) {
|
||||
$updateData['opening_balance'] = $request->opening_balance ?? 0;
|
||||
$updateData['balance'] = $request->opening_balance ?? 0;
|
||||
}
|
||||
|
||||
// Build meta explicitly
|
||||
$updateData['meta'] = [
|
||||
'account_number' => $request->account_number,
|
||||
'routing_number' => $request->routing_number,
|
||||
'upi_id' => $request->upi_id,
|
||||
'bank_name' => $request->bank_name,
|
||||
'account_holder' => $request->account_holder,
|
||||
'branch' => $request->branch,
|
||||
];
|
||||
|
||||
$payment_type->update($updateData);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $payment_type,
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
$paymentType = PaymentType::find($id);
|
||||
|
||||
if (!$paymentType) {
|
||||
return response()->json([
|
||||
'message' => __('Data not found.'),
|
||||
'data' => null,
|
||||
], 404);
|
||||
}
|
||||
|
||||
// Check if this payment type is used in any transaction
|
||||
$hasTransactions = $paymentType->transactions()->exists();
|
||||
|
||||
$balance = $paymentType->balance ?? 0;
|
||||
|
||||
if ($hasTransactions && $balance != 0) {
|
||||
return response()->json([
|
||||
'message' => __('Bank can’t be deleted. It has transactions or balance.')
|
||||
], 400);
|
||||
}
|
||||
|
||||
$paymentType->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data deleted successfully.'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
357
app/Http/Controllers/Api/BankTransactionController.php
Normal file
357
app/Http/Controllers/Api/BankTransactionController.php
Normal file
@@ -0,0 +1,357 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Helpers\HasUploader;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\Transaction;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class BankTransactionController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
public function index()
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
$payment_type_id = request('bank_id');
|
||||
|
||||
$data = Transaction::with('user:id,name', 'branch:id,name')
|
||||
->where('business_id', $business_id)
|
||||
->where(function ($query) use ($payment_type_id) {
|
||||
$query->where('payment_type_id', $payment_type_id)
|
||||
->orWhere('from_bank', $payment_type_id)
|
||||
->orWhere('to_bank', $payment_type_id);
|
||||
})
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$transaction = Transaction::with('user:id,name', 'branch:id,name')
|
||||
->where('business_id', $business_id)
|
||||
->where('id', $id)
|
||||
->first();
|
||||
|
||||
if (!$transaction) {
|
||||
return response()->json([
|
||||
'message' => __('Transaction not found.'),
|
||||
], 404);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Transaction fetched successfully.'),
|
||||
'data' => $transaction,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'from' => 'required|exists:payment_types,id',
|
||||
'type' => 'nullable|in:credit,debit',
|
||||
'transaction_type' => 'required|in:bank_to_bank,bank_to_cash,adjust_bank',
|
||||
'amount' => 'required|numeric|min:0.01',
|
||||
'date' => 'nullable|date',
|
||||
'image' => 'nullable|image|mimes:jpg,png,jpeg,svg',
|
||||
'note' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$business_id = auth()->user()->business_id;
|
||||
$amount = $request->amount ?? 0;
|
||||
$type = 'transfer';
|
||||
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
$fromBank = PaymentType::find($request->from);
|
||||
|
||||
// Prevent transferring to the same bank
|
||||
if ($request->transaction_type == 'bank_to_bank' && $request->from == $request->to) {
|
||||
return response()->json([
|
||||
'message' => 'Cannot transfer between the same bank account.'
|
||||
], 400);
|
||||
}
|
||||
|
||||
// Update balances based on transaction type
|
||||
if ($request->transaction_type == 'bank_to_bank') {
|
||||
$toBank = PaymentType::find($request->to);
|
||||
|
||||
if ($fromBank->balance < $amount) {
|
||||
return response()->json([
|
||||
'message' => 'Insufficient balance in source bank account.'
|
||||
], 400);
|
||||
}
|
||||
|
||||
$fromBank->decrement('balance', $amount);
|
||||
$toBank->increment('balance', $amount);
|
||||
|
||||
} elseif ($request->transaction_type == 'bank_to_cash') {
|
||||
if ($fromBank->balance < $amount) {
|
||||
return response()->json([
|
||||
'message' => 'Insufficient balance in selected bank.'
|
||||
], 400);
|
||||
}
|
||||
|
||||
$fromBank->decrement('balance', $amount);
|
||||
|
||||
} elseif ($request->transaction_type == 'adjust_bank') {
|
||||
$type = $request->type;
|
||||
if ($type == 'credit' && $fromBank->balance < $amount) {
|
||||
return response()->json([
|
||||
'message' => 'Cannot decrease below zero balance.'
|
||||
], 400);
|
||||
}
|
||||
if( $type == 'credit'){
|
||||
$fromBank->increment('balance', $amount);
|
||||
}else{
|
||||
$fromBank->decrement('balance', $amount);
|
||||
}
|
||||
}
|
||||
|
||||
$data = Transaction::create([
|
||||
'business_id' => $business_id,
|
||||
'user_id' => auth()->id(),
|
||||
'type' => $type,
|
||||
'platform' => 'bank',
|
||||
'transaction_type' => $request->transaction_type,
|
||||
'amount' => $amount,
|
||||
'from_bank' => $request->from,
|
||||
'to_bank' => ($request->transaction_type == 'bank_to_bank') ? $request->to : null,
|
||||
'date' => $request->date ?? now(),
|
||||
'image' => $request->image ? $this->upload($request, 'image') : NULL,
|
||||
'note' => $request->note,
|
||||
]);
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $data
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json([
|
||||
'message' => $e->getMessage()
|
||||
], 406);
|
||||
}
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$request->validate([
|
||||
'from' => 'required|exists:payment_types,id',
|
||||
'type' => 'nullable|in:credit,debit',
|
||||
'transaction_type' => 'required|in:bank_to_bank,bank_to_cash,adjust_bank',
|
||||
'amount' => 'required|numeric|min:0.01',
|
||||
'date' => 'nullable|date',
|
||||
'image' => 'nullable|image|mimes:jpg,png,jpeg,svg',
|
||||
'note' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$transaction = Transaction::findOrFail($id);
|
||||
$fromBank = PaymentType::find($request->from);
|
||||
$newAmount = $request->amount;
|
||||
$newType = $request->transaction_type;
|
||||
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
// Transaction type Same
|
||||
if ($transaction->transaction_type === $request->transaction_type) {
|
||||
|
||||
if ($newType === 'bank_to_bank') {
|
||||
$toBank = PaymentType::find($request->to);
|
||||
|
||||
// Adjust balance difference
|
||||
$diff = $newAmount - $transaction->amount;
|
||||
if ($fromBank->balance < $diff && $diff > 0) {
|
||||
return response()->json(['message' => 'Insufficient balance.'], 400);
|
||||
}
|
||||
|
||||
$fromBank->decrement('balance', $diff);
|
||||
$toBank->increment('balance', $diff);
|
||||
|
||||
} elseif ($newType === 'bank_to_cash') {
|
||||
$diff = $newAmount - $transaction->amount;
|
||||
if ($fromBank->balance < $diff && $diff > 0) {
|
||||
return response()->json(['message' => 'Insufficient balance.'], 400);
|
||||
}
|
||||
$fromBank->decrement('balance', $diff);
|
||||
|
||||
} elseif ($newType === 'adjust_bank') {
|
||||
$bankType = $request->type;
|
||||
$oldType = $transaction->type;
|
||||
$oldAmount = $transaction->amount;
|
||||
|
||||
if ($bankType === $oldType) {
|
||||
// Same type: adjust by difference
|
||||
$diff = $newAmount - $oldAmount;
|
||||
if ($bankType == 'credit') {
|
||||
$fromBank->increment('balance', $diff);
|
||||
} else {
|
||||
$fromBank->decrement('balance', $diff);
|
||||
}
|
||||
} else {
|
||||
// Different type: reverse old and apply new
|
||||
if ($oldType == 'credit') $fromBank->decrement('balance', $oldAmount);
|
||||
else $fromBank->increment('balance', $oldAmount);
|
||||
|
||||
if ($bankType == 'credit') $fromBank->increment('balance', $newAmount);
|
||||
else $fromBank->decrement('balance', $newAmount);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// Transaction type changed
|
||||
else {
|
||||
// Reverse old transaction completely
|
||||
if ($transaction->transaction_type === 'bank_to_bank') {
|
||||
$oldFrom = PaymentType::find($transaction->from_bank);
|
||||
$oldTo = PaymentType::find($transaction->to_bank);
|
||||
$oldFrom->increment('balance', $transaction->amount);
|
||||
$oldTo->decrement('balance', $transaction->amount);
|
||||
} elseif ($transaction->transaction_type === 'bank_to_cash') {
|
||||
$oldFrom = PaymentType::find($transaction->from_bank);
|
||||
$oldFrom->increment('balance', $transaction->amount);
|
||||
} elseif ($transaction->transaction_type === 'adjust_bank') {
|
||||
$oldFrom = PaymentType::find($transaction->from_bank);
|
||||
$transaction->type === 'credit'
|
||||
? $oldFrom->decrement('balance', $transaction->amount)
|
||||
: $oldFrom->increment('balance', $transaction->amount);
|
||||
}
|
||||
|
||||
// Apply new transaction
|
||||
if ($newType === 'bank_to_bank') {
|
||||
$toBank = PaymentType::find($request->to);
|
||||
if ($fromBank->balance < $newAmount) {
|
||||
return response()->json(['message' => 'Insufficient balance.'], 400);
|
||||
}
|
||||
$fromBank->decrement('balance', $newAmount);
|
||||
$toBank->increment('balance', $newAmount);
|
||||
} elseif ($newType === 'bank_to_cash') {
|
||||
if ($fromBank->balance < $newAmount) {
|
||||
return response()->json(['message' => 'Insufficient balance.'], 400);
|
||||
}
|
||||
$fromBank->decrement('balance', $newAmount);
|
||||
} elseif ($newType === 'adjust_bank') {
|
||||
if ($request->type == 'credit') $fromBank->increment('balance', $newAmount);
|
||||
else $fromBank->decrement('balance', $newAmount);
|
||||
}
|
||||
}
|
||||
|
||||
// Update transaction record
|
||||
$transaction->update([
|
||||
'type' => $newType === 'adjust_bank' ? $request->type : 'transfer',
|
||||
'transaction_type' => $newType,
|
||||
'amount' => $newAmount,
|
||||
'from_bank' => $request->from,
|
||||
'to_bank' => $newType === 'bank_to_bank' ? $request->to : null,
|
||||
'date' => $request->date ?? now(),
|
||||
'image' => $request->image ? $this->upload($request, 'image', $transaction->image) : $transaction->image,
|
||||
'note' => $request->note,
|
||||
]);
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $transaction,
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json(['message' => 'Error: ' . $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
|
||||
public function destroy(string $id)
|
||||
{
|
||||
$transaction = Transaction::findOrFail($id);
|
||||
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
$fromBank = PaymentType::find($transaction->from_bank);
|
||||
$toBank = PaymentType::find($transaction->to_bank);
|
||||
$amount = $transaction->amount;
|
||||
|
||||
// Allow only bank platform transactions to be deleted
|
||||
if ($transaction->platform !== 'bank') {
|
||||
return response()->json([
|
||||
'message' => 'Cannot delete here, please delete from ' . ucfirst($transaction->platform) . ' section.',
|
||||
], 400);
|
||||
}
|
||||
|
||||
// Reverse balance changes based on transaction type
|
||||
switch ($transaction->transaction_type) {
|
||||
case 'bank_to_bank':
|
||||
if ($toBank && $fromBank) {
|
||||
// Ensure receiver bank has enough balance before reversing
|
||||
if ($toBank->balance < $amount) {
|
||||
return response()->json([
|
||||
'message' => 'Insufficient balance in ' . $toBank->name . ' to reverse this transaction.',
|
||||
], 400);
|
||||
}
|
||||
|
||||
$fromBank->increment('balance', $amount);
|
||||
$toBank->decrement('balance', $amount);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'bank_to_cash':
|
||||
if ($fromBank) {
|
||||
$fromBank->increment('balance', $amount);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'adjust_bank':
|
||||
if ($fromBank) {
|
||||
if ($transaction->type === 'credit') {
|
||||
// Previously increased, so now decrease
|
||||
if ($fromBank->balance < $amount) {
|
||||
return response()->json([
|
||||
'message' => 'Insufficient balance in ' . $fromBank->name . ' to reverse this transaction.',
|
||||
], 400);
|
||||
}
|
||||
$fromBank->decrement('balance', $amount);
|
||||
} else {
|
||||
// Previously decreased, so now increase
|
||||
$fromBank->increment('balance', $amount);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (file_exists($transaction->image)) {
|
||||
Storage::delete($transaction->image);
|
||||
}
|
||||
|
||||
$transaction->delete();
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data deleted successfully.'),
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json(['message' => 'Error: ' . $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
26
app/Http/Controllers/Api/BulkUploadControler.php
Normal file
26
app/Http/Controllers/Api/BulkUploadControler.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Imports\ProductImport;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
|
||||
class BulkUploadControler extends Controller
|
||||
{
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'file' => 'required|file|mimes:xlsx,xls,csv'
|
||||
]);
|
||||
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
Excel::import(new ProductImport($businessId), $request->file('file'));
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Bulk upload successfully.')
|
||||
]);
|
||||
}
|
||||
}
|
||||
19
app/Http/Controllers/Api/BusinessCategoryController.php
Normal file
19
app/Http/Controllers/Api/BusinessCategoryController.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\BusinessCategory;
|
||||
|
||||
class BusinessCategoryController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$data = BusinessCategory::whereStatus(1)->latest()->get();
|
||||
|
||||
return response()->json([
|
||||
'data' => $data,
|
||||
'message' => __('Data fetched successfully.'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
386
app/Http/Controllers/Api/BusinessController.php
Normal file
386
app/Http/Controllers/Api/BusinessController.php
Normal file
@@ -0,0 +1,386 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Option;
|
||||
use App\Models\Plan;
|
||||
use App\Models\User;
|
||||
use App\Models\Business;
|
||||
use App\Models\Currency;
|
||||
use App\Helpers\HasUploader;
|
||||
use App\Models\UserCurrency;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\PlanSubscribe;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\PaymentType;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class BusinessController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
public function index()
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
// Ensure currency exists
|
||||
$business_currency = UserCurrency::select('id', 'name', 'code', 'symbol', 'position')
|
||||
->where('business_id', $business_id)
|
||||
->first();
|
||||
|
||||
if (!$business_currency) {
|
||||
$currency = Currency::where('is_default', 1)->first();
|
||||
UserCurrency::create([
|
||||
'name' => $currency->name,
|
||||
'code' => $currency->code,
|
||||
'rate' => $currency->rate,
|
||||
'business_id' => $business_id,
|
||||
'symbol' => $currency->symbol,
|
||||
'currency_id' => $currency->id,
|
||||
'position' => $currency->position,
|
||||
'country_name' => $currency->country_name,
|
||||
]);
|
||||
}
|
||||
|
||||
// Fetch user and business info
|
||||
$user = User::select('id', 'name', 'role', 'visibility', 'lang', 'email', 'branch_id', 'active_branch_id')->findOrFail(auth()->id());
|
||||
$business = Business::with('category:id,name', 'enrolled_plan:id,plan_id,business_id,price,duration,allow_multibranch', 'enrolled_plan.plan:id,subscriptionName')->findOrFail($business_id);
|
||||
|
||||
//admin setting option
|
||||
$generalValue = Option::where('key', 'general')->first()->value ?? [];
|
||||
$develop_by_level = $generalValue['admin_footer_text'] ?? '';
|
||||
$develop_by = $generalValue['admin_footer_link_text'] ?? '';
|
||||
$develop_by_link = $generalValue['admin_footer_link'] ?? '';
|
||||
|
||||
// Get business settings option
|
||||
$option = Option::where('key', 'business-settings')
|
||||
->where('value', 'LIKE', '%"business_id":%' . $business_id . '%')
|
||||
->get()
|
||||
->firstWhere('value.business_id', $business_id);
|
||||
|
||||
$invoice_logo = $option->value['invoice_logo'] ?? null;
|
||||
$a4_invoice_logo = $option->value['a4_invoice_logo'] ?? null;
|
||||
$thermal_invoice_logo = $option->value['thermal_invoice_logo'] ?? null;
|
||||
$invoice_scanner_logo = $option->value['invoice_scanner_logo'] ?? null;
|
||||
$sale_rounding_option = $option->value['sale_rounding_option'] ?? 'none';
|
||||
$note_label = $option->value['note_label'] ?? null;
|
||||
$note = $option->value['note'] ?? null;
|
||||
$gratitude_message = $option->value['gratitude_message'] ?? null;
|
||||
$warranty_void_label = $option->value['warranty_void_label'] ?? null;
|
||||
$warranty_void = $option->value['warranty_void'] ?? null;
|
||||
|
||||
$data = array_merge(
|
||||
$business->toArray(),
|
||||
['user' => $user->toArray() + ['active_branch' => $user->active_branch]],
|
||||
['business_currency' => $business_currency],
|
||||
['invoice_logo' => $invoice_logo],
|
||||
['a4_invoice_logo' => $a4_invoice_logo],
|
||||
['thermal_invoice_logo' => $thermal_invoice_logo],
|
||||
['invoice_scanner_logo' => $invoice_scanner_logo],
|
||||
['sale_rounding_option' => $sale_rounding_option],
|
||||
['invoice_size' => !empty(invoice_setting()) && moduleCheck('ThermalPrinterAddon') ? invoice_setting() : null],
|
||||
['invoice_language' => !empty(invoice_language()) ? invoice_language() : ''],
|
||||
['note' => $note],
|
||||
['note_label' => $note_label],
|
||||
['gratitude_message' => $gratitude_message],
|
||||
['warranty_void_label' => $warranty_void_label],
|
||||
['warranty_void' => $warranty_void],
|
||||
['show_note' => (int) ($option->value['show_note'] ?? 0)],
|
||||
['show_gratitude_msg' => (int) ($option->value['show_gratitude_msg'] ?? 0)],
|
||||
['show_invoice_scanner_logo' => (int) ($option->value['show_invoice_scanner_logo'] ?? 0)],
|
||||
['show_a4_invoice_logo' => (int) ($option->value['show_a4_invoice_logo'] ?? 0)],
|
||||
['show_thermal_invoice_logo' => (int) ($option->value['show_thermal_invoice_logo'] ?? 0)],
|
||||
['show_warranty' => (int) ($option->value['show_warranty'] ?? 0)],
|
||||
['develop_by_level' => $develop_by_level],
|
||||
['develop_by' => $develop_by],
|
||||
['develop_by_link' => $develop_by_link],
|
||||
['branch_count' => branch_count()],
|
||||
[
|
||||
'addons' => [
|
||||
'AffiliateAddon' => moduleCheck('AffiliateAddon'),
|
||||
'MultiBranchAddon' => moduleCheck('MultiBranchAddon'),
|
||||
'WarehouseAddon' => moduleCheck('WarehouseAddon'),
|
||||
'ThermalPrinterAddon' => moduleCheck('ThermalPrinterAddon'),
|
||||
'HrmAddon' => moduleCheck('HrmAddon'),
|
||||
'CustomDomainAddon' => moduleCheck('CustomDomainAddon'),
|
||||
'SerialCodeAddon' => moduleCheck('SerialCodeAddon')
|
||||
]
|
||||
],
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'address' => 'nullable|max:250',
|
||||
'companyName' => 'required|max:250',
|
||||
'pictureUrl' => 'nullable|image|max:5120',
|
||||
'shopOpeningBalance' => 'nullable|numeric',
|
||||
'phoneNumber' => 'nullable',
|
||||
'business_category_id' => 'required|exists:business_categories,id',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
|
||||
$user = auth()->user();
|
||||
$free_plan = Plan::where('subscriptionPrice', '<=', 0)->orWhere('offerPrice', '<=', 0)->first();
|
||||
|
||||
$business = Business::create($request->except('pictureUrl') + [
|
||||
'phoneNumber' => $request->phoneNumber,
|
||||
'subscriptionDate' => $free_plan ? now() : NULL,
|
||||
'will_expire' => $free_plan ? now()->addDays($free_plan->duration) : NULL,
|
||||
'pictureUrl' => $request->pictureUrl ? $this->upload($request, 'pictureUrl') : NULL
|
||||
]);
|
||||
|
||||
PaymentType::create([
|
||||
'name' => "Cash",
|
||||
'business_id' => $business->id
|
||||
]);
|
||||
|
||||
$user->update([
|
||||
'business_id' => $business->id,
|
||||
'phone' => $request->phoneNumber,
|
||||
'name' => $business->companyName,
|
||||
]);
|
||||
|
||||
$currency = Currency::where('is_default', 1)->first();
|
||||
UserCurrency::create([
|
||||
'business_id' => $business->id,
|
||||
'currency_id' => $currency->id,
|
||||
'name' => $currency->name,
|
||||
'country_name' => $currency->country_name,
|
||||
'code' => $currency->code,
|
||||
'rate' => $currency->rate,
|
||||
'symbol' => $currency->symbol,
|
||||
'position' => $currency->position,
|
||||
]);
|
||||
|
||||
if ($free_plan) {
|
||||
$subscribe = PlanSubscribe::create([
|
||||
'plan_id' => $free_plan->id,
|
||||
'business_id' => $business->id,
|
||||
'duration' => $free_plan->duration,
|
||||
'allow_multibranch' => $free_plan->allow_multibranch,
|
||||
]);
|
||||
|
||||
$business->update([
|
||||
'plan_subscribe_id' => $subscribe->id,
|
||||
]);
|
||||
}
|
||||
|
||||
Cache::forget('plan-data-' . $business->id);
|
||||
|
||||
DB::commit();
|
||||
return response()->json([
|
||||
'message' => __('Business setup completed.'),
|
||||
]);
|
||||
} catch (\Throwable $th) {
|
||||
DB::rollback();
|
||||
return response()->json(__('Something went wrong, Please contact with admin.'), 403);
|
||||
}
|
||||
}
|
||||
|
||||
public function update(Request $request, Business $business)
|
||||
{
|
||||
$request->validate([
|
||||
'address' => 'nullable|max:250',
|
||||
'companyName' => 'nullable|required_if:sale_rounding_option,!=,null|max:250',
|
||||
'business_category_id' => 'nullable|required_if:sale_rounding_option,!=,null|exists:business_categories,id',
|
||||
'pictureUrl' => 'nullable|image|max:5120',
|
||||
'show_company_name' => 'nullable|boolean',
|
||||
'show_phone_number' => 'nullable|boolean',
|
||||
'show_address' => 'nullable|boolean',
|
||||
'show_email' => 'nullable|boolean',
|
||||
'show_vat' => 'nullable|boolean',
|
||||
'invoice_logo' => 'nullable|image|max:5120',
|
||||
'a4_invoice_logo' => 'nullable|image|max:5120',
|
||||
'thermal_invoice_logo' => 'nullable|image|max:5120',
|
||||
'invoice_scanner_logo' => 'nullable|image|max:5120',
|
||||
'sale_rounding_option' => 'nullable|in:none,round_up,nearest_whole_number,nearest_0.05,nearest_0.1,nearest_0.5',
|
||||
'phoneNumber' => 'nullable',
|
||||
'invoice_size' => 'nullable|string|max:100',
|
||||
'invoice_language' => 'nullable|string|max:100',
|
||||
'gratitude_message' => 'nullable|string|max:100',
|
||||
'warranty_void_label' => 'nullable|string',
|
||||
'warranty_void' => 'nullable|string',
|
||||
'show_note' => 'nullable|boolean',
|
||||
'show_gratitude_msg' => 'nullable|boolean',
|
||||
'show_invoice_scanner_logo' => 'nullable|boolean',
|
||||
'show_a4_invoice_logo' => 'nullable|boolean',
|
||||
'show_thermal_invoice_logo' => 'nullable|boolean',
|
||||
'show_warranty' => 'nullable|boolean',
|
||||
]);
|
||||
|
||||
$business->update([
|
||||
'meta' => [
|
||||
'show_company_name' => (int) ($request->show_company_name ?? 0),
|
||||
'show_phone_number' => (int) ($request->show_phone_number ?? 0),
|
||||
'show_address' => (int) ($request->show_address ?? 0),
|
||||
'show_email' => (int) ($request->show_email ?? 0),
|
||||
'show_vat' => (int) ($request->show_vat ?? 0),
|
||||
]
|
||||
]);
|
||||
|
||||
// Update when sale_rounding_option is not provided
|
||||
if (!$request->sale_rounding_option) {
|
||||
auth()->user()->update([
|
||||
'name' => $request->companyName,
|
||||
'phone' => $request->phoneNumber,
|
||||
]);
|
||||
|
||||
$business->update($request->except('pictureUrl', 'meta') + [
|
||||
'pictureUrl' => $request->pictureUrl ? $this->upload($request, 'pictureUrl', $business->pictureUrl) : $business->pictureUrl,
|
||||
]);
|
||||
}
|
||||
|
||||
// Update or insert business settings
|
||||
$setting = Option::where('key', 'business-settings')
|
||||
->where('value', 'LIKE', '%"business_id":%' . $business->id . '%')
|
||||
->get()
|
||||
->firstWhere('value.business_id', $business->id);
|
||||
|
||||
$invoiceLogo = $request->invoice_logo ? $this->upload($request, 'invoice_logo', $setting->value['invoice_logo'] ?? null) : ($setting->value['invoice_logo'] ?? null);
|
||||
$a4_invoice_logo = $request->a4_invoice_logo ? $this->upload($request, 'a4_invoice_logo', $setting->value['a4_invoice_logo'] ?? null) : ($setting->value['a4_invoice_logo'] ?? null);
|
||||
$thermal_invoice_logo = $request->thermal_invoice_logo ? $this->upload($request, 'thermal_invoice_logo', $setting->value['thermal_invoice_logo'] ?? null) : ($setting->value['thermal_invoice_logo'] ?? null);
|
||||
$invoice_scanner_logo = $request->invoice_scanner_logo ? $this->upload($request, 'invoice_scanner_logo', $setting->value['invoice_scanner_logo'] ?? null) : ($setting->value['invoice_scanner_logo'] ?? null);
|
||||
|
||||
$settingData = [
|
||||
'business_id' => $business->id,
|
||||
'invoice_logo' => $invoiceLogo,
|
||||
'a4_invoice_logo' => $a4_invoice_logo,
|
||||
'thermal_invoice_logo' => $thermal_invoice_logo,
|
||||
'invoice_scanner_logo' => $invoice_scanner_logo,
|
||||
'sale_rounding_option' => $request->sale_rounding_option ?? 'none',
|
||||
'note_label' => $request->note_label,
|
||||
'note' => $request->note,
|
||||
'gratitude_message' => $request->gratitude_message,
|
||||
'warranty_void_label' => $request->warranty_void_label,
|
||||
'warranty_void' => $request->warranty_void,
|
||||
'vat_name' => $request->vat_name,
|
||||
'vat_no' => $request->vat_no,
|
||||
'show_note' => $request->show_note ?? 0,
|
||||
'show_gratitude_msg' => $request->show_gratitude_msg ?? 0,
|
||||
'show_invoice_scanner_logo' => $request->show_invoice_scanner_logo ?? 0,
|
||||
'show_a4_invoice_logo' => $request->show_a4_invoice_logo ?? 0,
|
||||
'show_thermal_invoice_logo' => $request->show_thermal_invoice_logo ?? 0,
|
||||
'show_warranty' => $request->show_warranty ?? 0,
|
||||
];
|
||||
|
||||
if ($setting) {
|
||||
$setting->update([
|
||||
'value' => array_merge($setting->value, $settingData),
|
||||
]);
|
||||
} else {
|
||||
Option::create([
|
||||
'key' => 'business-settings',
|
||||
'value' => $settingData,
|
||||
]);
|
||||
}
|
||||
|
||||
// Update Invoice Settings
|
||||
if ($request->filled('invoice_size')) {
|
||||
$invoiceKey = 'invoice_setting_' . $business->id;
|
||||
|
||||
Option::updateOrCreate(
|
||||
['key' => $invoiceKey],
|
||||
['value' => $request->invoice_size]
|
||||
);
|
||||
|
||||
Cache::forget($invoiceKey);
|
||||
}
|
||||
|
||||
if ($request->filled('invoice_language')) {
|
||||
$invoice_language_key = 'invoice_language_' . $business->id;
|
||||
|
||||
Option::updateOrCreate(
|
||||
['key' => $invoice_language_key],
|
||||
['value' => $request->invoice_language]
|
||||
);
|
||||
|
||||
Cache::forget($invoice_language_key);
|
||||
}
|
||||
|
||||
Cache::forget("business_setting_{$business->id}");
|
||||
Cache::forget("business_sale_rounding_{$business->id}");
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'business' => $business,
|
||||
'invoice_logo' => $invoiceLogo,
|
||||
'a4_invoice_logo' => $a4_invoice_logo,
|
||||
'thermal_invoice_logo' => $thermal_invoice_logo,
|
||||
'invoice_scanner_logo' => $invoice_scanner_logo,
|
||||
'sale_rounding_option' => $request->sale_rounding_option,
|
||||
'invoice_size' => $request->invoice_size,
|
||||
'invoice_language' => $request->invoice_language,
|
||||
'note_label' => $request->note_label,
|
||||
'note' => $request->note,
|
||||
'gratitude_message' => $request->gratitude_message,
|
||||
'warranty_void_label' => $request->warranty_void_label,
|
||||
'warranty_void' => $request->warranty_void,
|
||||
'vat_name' => $request->vat_name,
|
||||
'vat_no' => $request->vat_no,
|
||||
'show_note' => (int) $request->show_note ?? 0,
|
||||
'show_gratitude_msg' => (int) $request->show_gratitude_msg ?? 0,
|
||||
'show_invoice_scanner_logo' => (int) $request->show_invoice_scanner_logo ?? 0,
|
||||
'show_a4_invoice_logo' => (int) $request->show_a4_invoice_logo ?? 0,
|
||||
'show_thermal_invoice_logo' => (int) $request->show_thermal_invoice_logo ?? 0,
|
||||
'show_warranty' => (int) $request->show_warranty ?? 0,
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateExpireDate(Request $request)
|
||||
{
|
||||
$days = $request->query('days', 0);
|
||||
$operation = $request->query('operation');
|
||||
$business = Business::where('id', auth()->user()->business_id)->first();
|
||||
if (!$business) {
|
||||
return response()->json([
|
||||
'message' => 'Business not found.',
|
||||
], 404);
|
||||
}
|
||||
if ($operation === 'add') {
|
||||
$business->will_expire = now()->addDays($days);
|
||||
} elseif ($operation === 'sub') {
|
||||
$business->will_expire = now()->subDays($days);
|
||||
} else {
|
||||
return response()->json([
|
||||
'message' => 'Invalid operation. Use "add" or "sub".',
|
||||
], 400);
|
||||
}
|
||||
$business->save();
|
||||
return response()->json([
|
||||
'message' => 'Expiry date updated successfully.',
|
||||
'will_expire' => $business->will_expire,
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteBusiness(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'password' => 'required|string',
|
||||
]);
|
||||
|
||||
$user = auth()->user();
|
||||
|
||||
if (!Hash::check($request->password, $user->password)) {
|
||||
return response()->json([
|
||||
'message' => __('The provided password is incorrect.'),
|
||||
], 406);
|
||||
}
|
||||
|
||||
Business::where('id', $user->business_id)->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data deleted successfully.'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Option;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
|
||||
class BusinessCurrencySettingController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
$currency_setting_key = 'currency_setting_' . $businessId;
|
||||
$currency_setting = Option::where('key', $currency_setting_key)->first();
|
||||
|
||||
if ($currency_setting) {
|
||||
return response()->json([
|
||||
'message' => __('Currency data fetched successfully.'),
|
||||
'currency_data' => $currency_setting->value,
|
||||
]);
|
||||
} else {
|
||||
return response()->json([
|
||||
'message' => __('Currency not found.'),
|
||||
'currency_data' => null,
|
||||
], 404);
|
||||
}
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'currency' => 'required|string|max:100|in:us,european',
|
||||
]);
|
||||
|
||||
$key = 'currency_setting_' . auth()->user()->business_id;
|
||||
|
||||
Option::updateOrCreate(
|
||||
['key' => $key],
|
||||
['value' => $request->currency]
|
||||
);
|
||||
|
||||
Cache::forget($key);
|
||||
|
||||
return response()->json(__('Currency setting updated successfully.'));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Option;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class BusinessInvoiceSettingController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
$invoiceSetting = Option::where('key', 'invoice_settings')
|
||||
->where('value', 'LIKE', '%"business_id":%' . $businessId . '%')
|
||||
->get()
|
||||
->firstWhere('value.business_id', $businessId);
|
||||
|
||||
if ($invoiceSetting && isset($invoiceSetting->value['invoice_size'])) {
|
||||
return response()->json([
|
||||
'message' => __('Invoice size fetched successfully.'),
|
||||
'invoice_size' => $invoiceSetting->value['invoice_size'],
|
||||
]);
|
||||
} else {
|
||||
return response()->json([
|
||||
'message' => __('Invoice size not found.'),
|
||||
'invoice_size' => null,
|
||||
], 404);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateInvoice(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'invoice_size' => 'required|string|max:100|in:a4,3_inch_80mm,2_inch_58mm',
|
||||
]);
|
||||
|
||||
$key = 'invoice_setting_' . auth()->user()->business_id;
|
||||
|
||||
Option::updateOrCreate(
|
||||
['key' => $key],
|
||||
['value' => $request->invoice_size]
|
||||
);
|
||||
|
||||
Cache::forget($key);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Invoice size updated successfully.'),
|
||||
]);
|
||||
|
||||
}
|
||||
}
|
||||
307
app/Http/Controllers/Api/CashController.php
Normal file
307
app/Http/Controllers/Api/CashController.php
Normal file
@@ -0,0 +1,307 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Helpers\HasUploader;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\Transaction;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class CashController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$data = Transaction::with('user:id,name')
|
||||
->where('business_id', $business_id)
|
||||
->whereIn('transaction_type', ['cash_payment', 'bank_to_cash', 'cash_to_bank', 'adjust_cash', 'cheque_to_cash'])
|
||||
->when($request->duration, function ($query) use ($request) {
|
||||
$today = Carbon::today();
|
||||
|
||||
if ($request->duration === 'today') {
|
||||
$query->whereDate('date', $today);
|
||||
} elseif ($request->duration === 'yesterday') {
|
||||
$query->whereDate('date', Carbon::yesterday());
|
||||
} elseif ($request->duration === 'last_seven_days') {
|
||||
$startDate = Carbon::now()->subDays(7)->format('Y-m-d');
|
||||
$endDate = Carbon::now()->format('Y-m-d');
|
||||
$query->whereDate('date', '>=', $startDate)
|
||||
->whereDate('date', '<=', $endDate);
|
||||
} elseif ($request->duration === 'last_thirty_days') {
|
||||
$startDate = Carbon::now()->subDays(30)->format('Y-m-d');
|
||||
$endDate = Carbon::now()->format('Y-m-d');
|
||||
$query->whereDate('date', '>=', $startDate)
|
||||
->whereDate('date', '<=', $endDate);
|
||||
} elseif ($request->duration === 'current_month') {
|
||||
$startDate = Carbon::now()->startOfMonth()->format('Y-m-d');
|
||||
$endDate = Carbon::now()->endOfMonth()->format('Y-m-d');
|
||||
$query->whereDate('date', '>=', $startDate)
|
||||
->whereDate('date', '<=', $endDate);
|
||||
} elseif ($request->duration === 'last_month') {
|
||||
$startDate = Carbon::now()->subMonth()->startOfMonth()->format('Y-m-d');
|
||||
$endDate = Carbon::now()->subMonth()->endOfMonth()->format('Y-m-d');
|
||||
$query->whereDate('date', '>=', $startDate)
|
||||
->whereDate('date', '<=', $endDate);
|
||||
} elseif ($request->duration === 'current_year') {
|
||||
$startDate = Carbon::now()->startOfYear()->format('Y-m-d');
|
||||
$endDate = Carbon::now()->endOfYear()->format('Y-m-d');
|
||||
$query->whereDate('date', '>=', $startDate)
|
||||
->whereDate('date', '<=', $endDate);
|
||||
} elseif ($request->duration === 'custom_date' && $request->from_date && $request->to_date) {
|
||||
$startDate = Carbon::parse($request->from_date)->format('Y-m-d');
|
||||
$endDate = Carbon::parse($request->to_date)->format('Y-m-d');
|
||||
$query->whereDate('date', '>=', $startDate)
|
||||
->whereDate('date', '<=', $endDate);
|
||||
}
|
||||
})
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
$total_balance = cash_balance();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
'total_balance' => $total_balance,
|
||||
]);
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$transaction = Transaction::with('user:id,name', 'branch:id,name')
|
||||
->where('business_id', $business_id)
|
||||
->where('id', $id)
|
||||
->first();
|
||||
|
||||
if (!$transaction) {
|
||||
return response()->json([
|
||||
'message' => __('Transaction not found.'),
|
||||
], 404);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Transaction fetched successfully.'),
|
||||
'data' => $transaction,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'to' => 'nullable|exists:payment_types,id',
|
||||
'type' => 'nullable|in:credit,debit',
|
||||
'transaction_type' => 'required|in:cash_to_bank,adjust_cash',
|
||||
'amount' => 'required|numeric|min:0.01',
|
||||
'date' => 'nullable|date',
|
||||
'image' => 'nullable|image|mimes:jpg,png,jpeg,svg',
|
||||
'note' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$business_id = auth()->user()->business_id;
|
||||
$amount = $request->amount ?? 0;
|
||||
$type = 'transfer';
|
||||
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
// Cash to Bank
|
||||
if ($request->transaction_type === 'cash_to_bank') {
|
||||
$toBank = PaymentType::findOrFail($request->to);
|
||||
// increase target bank balance
|
||||
$toBank->increment('balance', $amount);
|
||||
|
||||
// Adjust Cash
|
||||
} elseif ($request->transaction_type === 'adjust_cash') {
|
||||
$type = $request->type;
|
||||
}
|
||||
|
||||
// Store transaction record
|
||||
$data = Transaction::create([
|
||||
'business_id' => $business_id,
|
||||
'user_id' => auth()->id(),
|
||||
'type' => $type,
|
||||
'platform' => 'cash',
|
||||
'transaction_type' => $request->transaction_type,
|
||||
'amount' => $amount,
|
||||
'from_bank' => null,
|
||||
'to_bank' => ($request->transaction_type === 'cash_to_bank') ? $request->to : null,
|
||||
'date' => $request->date ?? now(),
|
||||
'image' => $request->image ? $this->upload($request, 'image') : NULL,
|
||||
'note' => $request->note,
|
||||
]);
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $data
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
'message' => 'Error: ' . $e->getMessage(),
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$request->validate([
|
||||
'to' => 'nullable|exists:payment_types,id',
|
||||
'type' => 'nullable|in:credit,debit',
|
||||
'transaction_type' => 'required|in:cash_to_bank,adjust_cash',
|
||||
'amount' => 'required|numeric|min:0.01',
|
||||
'date' => 'nullable|date',
|
||||
'image' => 'nullable|image|mimes:jpg,png,jpeg,svg',
|
||||
'note' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$transaction = Transaction::findOrFail($id);
|
||||
$newAmount = $request->amount ?? 0;
|
||||
$newTransactionType = $request->transaction_type;
|
||||
$type = 'transfer';
|
||||
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
// Transaction type is the same
|
||||
if ($transaction->transaction_type === $newTransactionType) {
|
||||
if ($newTransactionType === 'cash_to_bank') {
|
||||
$toBank = PaymentType::findOrFail($request->to);
|
||||
|
||||
// Adjust balance difference
|
||||
$diff = $newAmount - $transaction->amount;
|
||||
|
||||
// Prevent negative balance
|
||||
if ($toBank->balance + $diff < 0) {
|
||||
return response()->json([
|
||||
'message' => 'Cannot update: updated bank balance would be negative.'
|
||||
], 400);
|
||||
}
|
||||
|
||||
$toBank->increment('balance', $diff);
|
||||
|
||||
} elseif ($newTransactionType === 'adjust_cash') {
|
||||
$type = $request->type;
|
||||
}
|
||||
}
|
||||
// Transaction type changed
|
||||
else {
|
||||
// Reverse old transaction effect
|
||||
if ($transaction->transaction_type === 'cash_to_bank' && $transaction->to_bank) {
|
||||
$prevBank = PaymentType::find($transaction->to_bank);
|
||||
if ($prevBank) {
|
||||
if ($prevBank->balance < $transaction->amount) {
|
||||
return response()->json([
|
||||
'message' => 'Cannot update: insufficient balance in ' . $prevBank->name . ' to reverse previous transaction.'
|
||||
], 400);
|
||||
}
|
||||
$prevBank->decrement('balance', $transaction->amount);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply new transaction effect
|
||||
if ($newTransactionType === 'cash_to_bank') {
|
||||
$toBank = PaymentType::findOrFail($request->to);
|
||||
$toBank->increment('balance', $newAmount);
|
||||
$type = 'transfer';
|
||||
} elseif ($newTransactionType === 'adjust_cash') {
|
||||
$type = $request->type;
|
||||
}
|
||||
}
|
||||
|
||||
// Update transaction record
|
||||
$transaction->update([
|
||||
'type' => $type,
|
||||
'transaction_type' => $newTransactionType,
|
||||
'amount' => $newAmount,
|
||||
'to_bank' => ($newTransactionType === 'cash_to_bank') ? $request->to : null,
|
||||
'date' => $request->date ?? now(),
|
||||
'image' => $request->image ? $this->upload($request, 'image') : $transaction->image,
|
||||
'note' => $request->note,
|
||||
]);
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $transaction,
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
'message' => 'Error: ' . $e->getMessage(),
|
||||
], 500);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function destroy(string $id)
|
||||
{
|
||||
|
||||
$transaction = Transaction::findOrFail($id);
|
||||
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
// Allow only "cash" platform transactions to be deleted
|
||||
if ($transaction->platform !== 'cash') {
|
||||
return response()->json([
|
||||
'message' => 'Cannot delete here, please delete from ' . ucfirst($transaction->platform) . ' section.',
|
||||
], 400);
|
||||
}
|
||||
|
||||
$amount = $transaction->amount;
|
||||
$toBank = $transaction->to_bank ? PaymentType::find($transaction->to_bank) : null;
|
||||
|
||||
// Reverse balance changes based on transaction type
|
||||
switch ($transaction->transaction_type) {
|
||||
case 'cash_to_bank':
|
||||
if ($toBank) {
|
||||
// Ensure bank has enough balance to reverse
|
||||
if ($toBank->balance < $amount) {
|
||||
return response()->json([
|
||||
'message' => 'Cannot delete: bank balance would go negative.',
|
||||
], 400);
|
||||
}
|
||||
$toBank->decrement('balance', $amount);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'adjust_cash':
|
||||
// Cash is static, so no bank adjustments needed
|
||||
break;
|
||||
}
|
||||
|
||||
if (file_exists($transaction->image)) {
|
||||
Storage::delete($transaction->image);
|
||||
}
|
||||
|
||||
$transaction->delete();
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data deleted successfully.'),
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
'message' => 'Error: ' . $e->getMessage(),
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
297
app/Http/Controllers/Api/ChequeController.php
Normal file
297
app/Http/Controllers/Api/ChequeController.php
Normal file
@@ -0,0 +1,297 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Income;
|
||||
use App\Models\Party;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\Sale;
|
||||
use App\Models\Transaction;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class ChequeController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$data = Transaction::with(['user:id,name','paymentType:id,name'])
|
||||
->where('business_id', $business_id)
|
||||
->whereIn('transaction_type', ['cheque_payment'])
|
||||
->when($request->duration, function ($query) use ($request) {
|
||||
$today = Carbon::today();
|
||||
|
||||
if ($request->duration === 'today') {
|
||||
$query->whereDate('date', $today);
|
||||
} elseif ($request->duration === 'yesterday') {
|
||||
$query->whereDate('date', Carbon::yesterday());
|
||||
} elseif ($request->duration === 'last_seven_days') {
|
||||
$startDate = Carbon::now()->subDays(7)->format('Y-m-d');
|
||||
$endDate = Carbon::now()->format('Y-m-d');
|
||||
$query->whereDate('date', '>=', $startDate)
|
||||
->whereDate('date', '<=', $endDate);
|
||||
} elseif ($request->duration === 'last_thirty_days') {
|
||||
$startDate = Carbon::now()->subDays(30)->format('Y-m-d');
|
||||
$endDate = Carbon::now()->format('Y-m-d');
|
||||
$query->whereDate('date', '>=', $startDate)
|
||||
->whereDate('date', '<=', $endDate);
|
||||
} elseif ($request->duration === 'current_month') {
|
||||
$startDate = Carbon::now()->startOfMonth()->format('Y-m-d');
|
||||
$endDate = Carbon::now()->endOfMonth()->format('Y-m-d');
|
||||
$query->whereDate('date', '>=', $startDate)
|
||||
->whereDate('date', '<=', $endDate);
|
||||
} elseif ($request->duration === 'last_month') {
|
||||
$startDate = Carbon::now()->subMonth()->startOfMonth()->format('Y-m-d');
|
||||
$endDate = Carbon::now()->subMonth()->endOfMonth()->format('Y-m-d');
|
||||
$query->whereDate('date', '>=', $startDate)
|
||||
->whereDate('date', '<=', $endDate);
|
||||
} elseif ($request->duration === 'current_year') {
|
||||
$startDate = Carbon::now()->startOfYear()->format('Y-m-d');
|
||||
$endDate = Carbon::now()->endOfYear()->format('Y-m-d');
|
||||
$query->whereDate('date', '>=', $startDate)
|
||||
->whereDate('date', '<=', $endDate);
|
||||
} elseif ($request->duration === 'custom_date' && $request->from_date && $request->to_date) {
|
||||
$startDate = Carbon::parse($request->from_date)->format('Y-m-d');
|
||||
$endDate = Carbon::parse($request->to_date)->format('Y-m-d');
|
||||
$query->whereDate('date', '>=', $startDate)
|
||||
->whereDate('date', '<=', $endDate);
|
||||
}
|
||||
})
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'transaction_id' => 'required|exists:transactions,id',
|
||||
'date' => 'nullable|date',
|
||||
'note' => 'nullable|string',
|
||||
'payment_type' => [
|
||||
'required',
|
||||
function ($attribute, $value, $fail) {
|
||||
if ($value !== 'cash' && !PaymentType::where('id', $value)->exists()) {
|
||||
$fail(__('The selected payment type is invalid.'));
|
||||
}
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$transaction = Transaction::findOrFail($request->transaction_id);
|
||||
$amount = $transaction->amount;
|
||||
$platform = strtolower($transaction->platform);
|
||||
|
||||
$transaction->update([
|
||||
'type' => 'deposit',
|
||||
]);
|
||||
|
||||
$newTransactionData = [
|
||||
'business_id' => $business_id,
|
||||
'user_id' => auth()->id(),
|
||||
'type' => 'credit',
|
||||
'platform' => 'cheque',
|
||||
'amount' => $amount,
|
||||
'date' => $request->date ?? now(),
|
||||
'note' => $request->note,
|
||||
'meta' => [
|
||||
'source_transaction_id' => $request->transaction_id ?? null,
|
||||
],
|
||||
];
|
||||
|
||||
// Cheque deposited into Cash
|
||||
if ($request->payment_type === 'cash') {
|
||||
$newTransactionData['transaction_type'] = 'cheque_to_cash';
|
||||
$newTransactionData['payment_type_id'] = null;
|
||||
} else {
|
||||
// Cheque deposited into Bank
|
||||
$toBank = PaymentType::findOrFail($request->payment_type);
|
||||
$toBank->increment('balance', $amount);
|
||||
|
||||
$newTransactionData['transaction_type'] = 'cheque_to_bank';
|
||||
$newTransactionData['payment_type_id'] = $toBank->id;
|
||||
}
|
||||
|
||||
Transaction::create($newTransactionData);
|
||||
|
||||
// update related platform
|
||||
if ($platform == 'sale') {
|
||||
$sale = Sale::find($transaction->reference_id);
|
||||
|
||||
updateBalance($amount, 'increment');
|
||||
|
||||
$newPaid = $sale->paidAmount + $amount;
|
||||
$expectedTotal = $sale->paidAmount + $sale->dueAmount;
|
||||
$newChange = max($newPaid - $expectedTotal, 0);
|
||||
$newDue = max($sale->dueAmount - $amount, 0);
|
||||
|
||||
$sale->update([
|
||||
'paidAmount' => $newPaid,
|
||||
'change_amount' => $sale->change_amount + $newChange,
|
||||
'dueAmount' => $newDue,
|
||||
'isPaid' => $newDue > 0 ? 0 : 1,
|
||||
]);
|
||||
|
||||
// update party due
|
||||
if ($sale->party_id) {
|
||||
$party = Party::find($sale->party_id);
|
||||
if ($party) {
|
||||
$party->decrement('due', min($amount, $party->due));
|
||||
}
|
||||
}
|
||||
} elseif ($transaction->platform == 'income') {
|
||||
$income = Income::find($transaction->reference_id);
|
||||
$income->increment('amount', $transaction->amount);
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $transaction
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json([
|
||||
'message' => $e->getMessage()
|
||||
], 406);
|
||||
}
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$transaction = Transaction::with('user:id,name', 'branch:id,name')
|
||||
->where('business_id', $business_id)
|
||||
->where('id', $id)
|
||||
->first();
|
||||
|
||||
if (!$transaction) {
|
||||
return response()->json([
|
||||
'message' => __('Transaction not found.'),
|
||||
], 404);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Transaction fetched successfully.'),
|
||||
'data' => $transaction,
|
||||
]);
|
||||
}
|
||||
|
||||
public function reopen($TransactionId)
|
||||
{
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
// original cheque payment
|
||||
$originalTxn = Transaction::findOrFail($TransactionId);
|
||||
|
||||
// Must be cheque_payment
|
||||
if ($originalTxn->transaction_type !== 'cheque_payment') {
|
||||
return response()->json(['message' => __('This transaction cannot be reopened.')], 400);
|
||||
}
|
||||
|
||||
$amount = $originalTxn->amount;
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$depositTxn = Transaction::where('platform', 'cheque')
|
||||
->where('meta->source_transaction_id', $originalTxn->id)
|
||||
->first();
|
||||
|
||||
if (!$depositTxn) {
|
||||
return response()->json(['message' => __('Deposited cheque record not found.')], 400);
|
||||
}
|
||||
|
||||
// Reverse bank balance only if cheque_to_bank
|
||||
if ($depositTxn->transaction_type === 'cheque_to_bank' && $depositTxn->payment_type_id) {
|
||||
$bank = PaymentType::find($depositTxn->payment_type_id);
|
||||
if ($bank) {
|
||||
$bank->decrement('balance', $amount);
|
||||
}
|
||||
}
|
||||
|
||||
$platform = strtolower($originalTxn->platform);
|
||||
|
||||
// Reverse Sale or Income
|
||||
if ($platform == 'sale') {
|
||||
$sale = Sale::find($originalTxn->reference_id);
|
||||
if ($sale) {
|
||||
// Reverse paid, change, and due amounts
|
||||
$newPaid = $sale->paidAmount - $amount;
|
||||
$newDue = $sale->dueAmount + $amount;
|
||||
$newChange = max($sale->change_amount - max($sale->paidAmount - ($sale->paidAmount + $sale->dueAmount - $amount), 0), 0);
|
||||
|
||||
$sale->update([
|
||||
'paidAmount' => max($newPaid, 0),
|
||||
'change_amount' => max($newChange, 0),
|
||||
'dueAmount' => $newDue,
|
||||
'isPaid' => $newDue > 0 ? 0 : 1,
|
||||
]);
|
||||
|
||||
// Reverse party due if exists
|
||||
if ($sale->party_id) {
|
||||
$party = Party::find($sale->party_id);
|
||||
if ($party) {
|
||||
$party->increment('due', $amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif ($platform == 'income') {
|
||||
$income = Income::find($originalTxn->reference_id);
|
||||
if ($income) {
|
||||
$income->decrement('amount', $amount);
|
||||
}
|
||||
}
|
||||
|
||||
$reverseType = $depositTxn->transaction_type === 'cheque_to_cash' ? 'cash_to_cheque' : 'bank_to_cheque';
|
||||
|
||||
// Create reverse debit transaction
|
||||
Transaction::create([
|
||||
'business_id' => $business_id,
|
||||
'user_id' => auth()->id(),
|
||||
'type' => 'debit',
|
||||
'platform' => 'cheque',
|
||||
'amount' => $amount,
|
||||
'date' => now(),
|
||||
'note' => 'Cheque reopened',
|
||||
'transaction_type' => $reverseType,
|
||||
'payment_type_id' => $depositTxn->payment_type_id,
|
||||
'meta' => [
|
||||
'reverted_transaction_id' => $depositTxn->id
|
||||
]
|
||||
]);
|
||||
|
||||
$originalTxn->update([
|
||||
'type' => 'pending',
|
||||
]);
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $originalTxn
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => $e->getMessage()
|
||||
], 406);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
27
app/Http/Controllers/Api/DefaultLangController.php
Normal file
27
app/Http/Controllers/Api/DefaultLangController.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Party;
|
||||
use App\Models\Business;
|
||||
use App\Helpers\HasUploader;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PartyLedgerService;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class DefaultLangController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
public function index()
|
||||
{
|
||||
$default_lang = get_option('general')['default_lang'] ?? '';
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $default_lang,
|
||||
]);
|
||||
}
|
||||
}
|
||||
79
app/Http/Controllers/Api/ExpenseCategoryController.php
Normal file
79
app/Http/Controllers/Api/ExpenseCategoryController.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\ExpenseCategory;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ExpenseCategoryController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$data = ExpenseCategory::where('business_id', auth()->user()->business_id)->latest()->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'categoryName' => 'required|unique:expense_categories,categoryName,NULL,id,business_id,' . auth()->user()->business_id,
|
||||
]);
|
||||
|
||||
$data = ExpenseCategory::create($request->except('status') + [
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'status' => $request->status == 'true' ? 1 : 0,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$category = ExpenseCategory::findOrFail($id);
|
||||
|
||||
$request->validate([
|
||||
'categoryName' => [
|
||||
'required',
|
||||
'unique:expense_categories,categoryName,' . $category->id . ',id,business_id,' . auth()->user()->business_id,
|
||||
],
|
||||
]);
|
||||
|
||||
$category->update($request->except('status') + [
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'status' => $request->status == 'true' ? 1 : 0,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
$category = ExpenseCategory::findOrFail($id);
|
||||
$category->delete();
|
||||
return response()->json([
|
||||
'message' => __('Data deleted successfully.'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
318
app/Http/Controllers/Api/PartyController.php
Normal file
318
app/Http/Controllers/Api/PartyController.php
Normal file
@@ -0,0 +1,318 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Party;
|
||||
use App\Models\Business;
|
||||
use App\Helpers\HasUploader;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\PartyLedgerService;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class PartyController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
|
||||
public function index()
|
||||
{
|
||||
$user = auth()->user();
|
||||
$businessId = $user->business_id;
|
||||
$activeBranch = $user->active_branch;
|
||||
|
||||
$parties = Party::where('business_id', $businessId)
|
||||
->when(request('type'), function ($q) {
|
||||
$q->where('type', request('type'));
|
||||
})
|
||||
->withCount([
|
||||
'sales as sales_count' => function ($q) use ($activeBranch) {
|
||||
if (moduleCheck('MultiBranchAddon') && $activeBranch) {
|
||||
$q->where('branch_id', $activeBranch->id);
|
||||
}
|
||||
}
|
||||
])
|
||||
->withSum([
|
||||
'sales as total_sale_amount' => function ($q) use ($activeBranch) {
|
||||
if (moduleCheck('MultiBranchAddon') && $activeBranch) {
|
||||
$q->where('branch_id', $activeBranch->id);
|
||||
}
|
||||
}
|
||||
], 'totalAmount')
|
||||
->withSum([
|
||||
'sales as total_sale_paid' => function ($q) use ($activeBranch) {
|
||||
if (moduleCheck('MultiBranchAddon') && $activeBranch) {
|
||||
$q->where('branch_id', $activeBranch->id);
|
||||
}
|
||||
}
|
||||
], 'paidAmount')
|
||||
->withSum([
|
||||
'sales as total_sale_profit' => function ($q) use ($activeBranch) {
|
||||
$q->where('lossProfit', '>=', 0);
|
||||
if (moduleCheck('MultiBranchAddon') && $activeBranch) {
|
||||
$q->where('branch_id', $activeBranch->id);
|
||||
}
|
||||
}
|
||||
], 'lossProfit')
|
||||
->withSum([
|
||||
'sales as total_sale_loss' => function ($q) use ($activeBranch) {
|
||||
$q->where('lossProfit', '<', 0);
|
||||
if (moduleCheck('MultiBranchAddon') && $activeBranch) {
|
||||
$q->where('branch_id', $activeBranch->id);
|
||||
}
|
||||
}
|
||||
], 'lossProfit')
|
||||
->withCount([
|
||||
'purchases as purchases_count' => function ($q) use ($activeBranch) {
|
||||
if (moduleCheck('MultiBranchAddon') && $activeBranch) {
|
||||
$q->where('branch_id', $activeBranch->id);
|
||||
}
|
||||
}
|
||||
])
|
||||
->withSum([
|
||||
'purchases as total_purchase_amount' => function ($q) use ($activeBranch) {
|
||||
if (moduleCheck('MultiBranchAddon') && $activeBranch) {
|
||||
$q->where('branch_id', $activeBranch->id);
|
||||
}
|
||||
}
|
||||
], 'totalAmount')
|
||||
->withSum([
|
||||
'purchases as total_purchase_paid' => function ($q) use ($activeBranch) {
|
||||
if (moduleCheck('MultiBranchAddon') && $activeBranch) {
|
||||
$q->where('branch_id', $activeBranch->id);
|
||||
}
|
||||
}
|
||||
], 'paidAmount')
|
||||
->with([
|
||||
'sales' => function ($sq) use ($activeBranch) {
|
||||
$sq->select('id', 'party_id', 'branch_id');
|
||||
|
||||
if (moduleCheck('MultiBranchAddon') && $activeBranch) {
|
||||
$sq->where('branch_id', $activeBranch->id);
|
||||
}
|
||||
|
||||
$sq->with([
|
||||
'details' => function ($dq) {
|
||||
$dq->select(
|
||||
'id',
|
||||
'sale_id',
|
||||
'product_id',
|
||||
'quantities',
|
||||
'productPurchasePrice',
|
||||
'price',
|
||||
'lossProfit'
|
||||
)->with([
|
||||
'product:id,productName'
|
||||
]);
|
||||
}
|
||||
]);
|
||||
}
|
||||
])
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
$accessToMultiBranch = auth()->user()->accessToMultiBranch();
|
||||
|
||||
foreach ($parties as $party) {
|
||||
$branch_logic = $party->branch_id === ($activeBranch->id ?? false) || $accessToMultiBranch;
|
||||
|
||||
if ($activeBranch && moduleCheck('MultiBranchAddon')) {
|
||||
if ($party->type === 'Supplier') {
|
||||
if (!$branch_logic) {
|
||||
$party->due = $party->purchases_dues
|
||||
->where('branch_id', $activeBranch->id)
|
||||
->sum('dueAmount');
|
||||
}
|
||||
} else {
|
||||
if (!$branch_logic) {
|
||||
$party->due = $party->sales_dues
|
||||
->where('branch_id', $activeBranch->id)
|
||||
->sum('dueAmount');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$party->wallet = $branch_logic ? $party->wallet : 0;
|
||||
$party->opening_balance = $branch_logic ? $party->opening_balance : 0;
|
||||
$party->opening_balance_type = $branch_logic ? $party->opening_balance_type : null;
|
||||
|
||||
if ($party->type === 'Supplier') {
|
||||
$party->makeHidden([
|
||||
'sales_count',
|
||||
'total_sale_amount',
|
||||
'total_sale_paid',
|
||||
'total_sale_profit',
|
||||
'total_sale_loss',
|
||||
]);
|
||||
} else {
|
||||
$party->makeHidden([
|
||||
'purchases_count',
|
||||
'total_purchase_amount',
|
||||
'total_purchase_paid',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $parties,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'type' => 'required|string|in:Retailer,Dealer,Wholesaler,Supplier',
|
||||
'phone' => 'nullable|max:20|' . Rule::unique('parties')->where('business_id', $business_id),
|
||||
'image' => 'nullable|image|mimes:jpeg,png,jpg,svg',
|
||||
'address' => 'nullable|string|max:255',
|
||||
'credit_limit' => 'nullable|numeric|min:0|max:999999999999.99',
|
||||
'opening_balance' => 'nullable|numeric|min:-999999999999.99|max:999999999999.99',
|
||||
'opening_balance_type' => 'required|in:due,advance',
|
||||
]);
|
||||
|
||||
$data = Party::create($request->except('image', 'due', 'wallet', 'opening_balance', 'credit_limit') + [
|
||||
'due' => ($request->opening_balance_type == 'due') ? ($request->opening_balance ?? 0) : 0,
|
||||
'wallet' => ($request->opening_balance_type == 'advance') ? ($request->opening_balance ?? 0) : 0,
|
||||
'opening_balance' => $request->opening_balance ?? 0,
|
||||
'credit_limit' => $request->credit_limit ?? 0,
|
||||
'image' => $request->image ? $this->upload($request, 'image') : NULL,
|
||||
'business_id' => $business_id
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function show(Party $party)
|
||||
{
|
||||
if (env('MESSAGE_ENABLED')) {
|
||||
if ($party->due) {
|
||||
$business = Business::findOrFail($party->business_id);
|
||||
$response = sendMessage($party->phone, dueMessage($party, $business->companyName));
|
||||
|
||||
if ($response->successful()) {
|
||||
return response()->json([
|
||||
'message' => __('Message has been send successfully.'),
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Something went wrong, Please contact with admin.'),
|
||||
], 406);
|
||||
} else {
|
||||
return response()->json([
|
||||
'message' => __('This party has no due balance.'),
|
||||
], 406);
|
||||
}
|
||||
} else {
|
||||
return response()->json([
|
||||
'message' => __('Message has been disabled by admin.'),
|
||||
], 406);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, Party $party)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'type' => 'required|string|in:Retailer,Dealer,Wholesaler,Supplier',
|
||||
'phone' => 'nullable|max:20|unique:parties,phone,' . $party->id . ',id,business_id,' . auth()->user()->business_id,
|
||||
'image' => 'nullable|image|mimes:jpeg,png,jpg,svg',
|
||||
'address' => 'nullable|string|max:255',
|
||||
'credit_limit' => 'nullable|numeric|min:0|max:999999999999.99',
|
||||
'opening_balance' => 'nullable|numeric|min:-999999999999.99|max:999999999999.99',
|
||||
'opening_balance_type' => 'required|in:due,advance',
|
||||
]);
|
||||
|
||||
$branch_logic = $party->branch_id == auth()->user()->active_branch?->id;
|
||||
|
||||
// Previous
|
||||
$prevOpening = $party->opening_balance ?? 0;
|
||||
$prevType = $party->opening_balance_type;
|
||||
|
||||
// Current
|
||||
$currentOpening = $request->opening_balance ?? 0;
|
||||
$currentType = $request->opening_balance_type;
|
||||
|
||||
// Start with existing balance
|
||||
$due = $party->due;
|
||||
$wallet = $party->wallet;
|
||||
|
||||
if ($prevType == $currentType) {
|
||||
// Same type → adjust by difference
|
||||
if ($currentType == 'due') {
|
||||
$due += ($currentOpening - $prevOpening);
|
||||
} else {
|
||||
$wallet += ($currentOpening - $prevOpening);
|
||||
}
|
||||
} else {
|
||||
// Type changed → shift balances
|
||||
if ($prevType == 'due' && $currentType == 'advance') {
|
||||
$due -= $prevOpening;
|
||||
$wallet += $currentOpening;
|
||||
} elseif ($prevType == 'advance' && $currentType == 'due') {
|
||||
$wallet -= $prevOpening;
|
||||
$due += $currentOpening;
|
||||
}
|
||||
}
|
||||
|
||||
$party->update(
|
||||
$request->except('image', 'due', 'wallet', 'opening_balance', 'credit_limit', 'business_id') + [
|
||||
'due' => $branch_logic ? $due : $party->due,
|
||||
'wallet' => $branch_logic ? $wallet : $party->wallet,
|
||||
'opening_balance' => $currentOpening,
|
||||
'opening_balance_type' => $currentType,
|
||||
'credit_limit' => $request->credit_limit ?? $party->credit_limit,
|
||||
'image' => $request->image ? $this->upload($request, 'image', $party->image) : $party->image,
|
||||
]
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $party,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(Party $party)
|
||||
{
|
||||
if (!$party->canBeDeleted()) {
|
||||
return response()->json([
|
||||
'message' => __('This party cannot be deleted.'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
if (file_exists($party->image)) {
|
||||
Storage::delete($party->image);
|
||||
}
|
||||
|
||||
$party->delete();
|
||||
return response()->json([
|
||||
'message' => __('Data deleted successfully.'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function partyLedger(Request $request, $partyId, PartyLedgerService $service)
|
||||
{
|
||||
$ledger = $service->list($request, $partyId);
|
||||
|
||||
return response()->json([
|
||||
'data' => $ledger,
|
||||
]);
|
||||
}
|
||||
}
|
||||
69
app/Http/Controllers/Api/PaymentTypeController.php
Normal file
69
app/Http/Controllers/Api/PaymentTypeController.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\PaymentType;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class PaymentTypeController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$data = PaymentType::where('business_id', auth()->user()->business_id)->latest()->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => [
|
||||
'required',
|
||||
Rule::unique('payment_types')->where(function ($query) {
|
||||
return $query->where('business_id', auth()->user()->business_id);
|
||||
}),
|
||||
],
|
||||
]);
|
||||
|
||||
$data = PaymentType::create($request->all() + [
|
||||
'business_id' => auth()->user()->business_id
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
$payment_type = PaymentType::findOrFail($id);
|
||||
|
||||
$request->validate([
|
||||
'name' => 'required|unique:payment_types,name,' . $payment_type->id . ',id,business_id,' . auth()->user()->business_id,
|
||||
]);
|
||||
|
||||
$payment_type->update($request->all());
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $payment_type,
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(string $id)
|
||||
{
|
||||
$payment_type = PaymentType::findOrFail($id);
|
||||
$payment_type->delete();
|
||||
return response()->json([
|
||||
'message' => __('Data deleted successfully.'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
79
app/Http/Controllers/Api/ProducModelController.php
Normal file
79
app/Http/Controllers/Api/ProducModelController.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\ProductModel;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ProducModelController extends Controller
|
||||
{
|
||||
|
||||
public function index()
|
||||
{
|
||||
$data = ProductModel::where('business_id', auth()->user()->business_id)->latest()->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|unique:product_models,name,NULL,id,business_id,' . auth()->user()->business_id,
|
||||
]);
|
||||
|
||||
$data = ProductModel::create($request->all() + [
|
||||
'business_id' => auth()->user()->business_id
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
$product_model = ProductModel::find($id);
|
||||
if (!$product_model) {
|
||||
return response()->json([
|
||||
'message' => __('Model not found.'),
|
||||
'data' => null,
|
||||
], 404);
|
||||
}
|
||||
$request->validate([
|
||||
'name' => [
|
||||
'required',
|
||||
'unique:product_models,name,' . $product_model->id . ',id,business_id,' . auth()->user()->business_id,
|
||||
],
|
||||
]);
|
||||
|
||||
$product_model->update($request->all());
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $product_model,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function destroy(string $id)
|
||||
{
|
||||
$product_model = ProductModel::find($id);
|
||||
|
||||
if (!$product_model) {
|
||||
return response()->json([
|
||||
'message' => __('Model not found.'),
|
||||
], 404);
|
||||
}
|
||||
|
||||
$product_model->delete();
|
||||
return response()->json([
|
||||
'message' => __('Data deleted successfully.'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
142
app/Http/Controllers/Api/ProductSettingsController.php
Normal file
142
app/Http/Controllers/Api/ProductSettingsController.php
Normal file
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\ProductSetting;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ProductSettingsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$data = ProductSetting::where('business_id', auth()->user()->business_id)->first();
|
||||
|
||||
if ($data) {
|
||||
$responseData = $data;
|
||||
} else {
|
||||
$responseData = [
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'modules' => [
|
||||
// Default fields = "1"
|
||||
'show_product_type_single' => "1",
|
||||
'show_product_category' => "1",
|
||||
'show_alert_qty' => "1",
|
||||
'show_product_unit' => "1",
|
||||
'show_exclusive_price' => "1",
|
||||
'show_inclusive_price' => "1",
|
||||
'show_profit_percent' => "1",
|
||||
'show_product_sale_price' => "1",
|
||||
'show_product_price' => "1",
|
||||
'show_product_stock' => "1",
|
||||
|
||||
'default_sale_price' => null,
|
||||
'default_wholesale_price' => null,
|
||||
'default_dealer_price' => null,
|
||||
'default_batch_no' => null,
|
||||
'expire_date_type' => null,
|
||||
'mfg_date_type' => null,
|
||||
'default_expired_date' => null,
|
||||
'default_mfg_date' => null,
|
||||
|
||||
'show_product_code' => "0",
|
||||
'show_product_brand' => "0",
|
||||
'show_model_no' => "0",
|
||||
'show_product_manufacturer' => "0",
|
||||
'show_product_image' => "0",
|
||||
'show_vat_id' => "0",
|
||||
'show_vat_type' => "0",
|
||||
'show_action' => "0",
|
||||
'show_product_dealer_price' => "0",
|
||||
'show_product_wholesale_price' => "0",
|
||||
'show_batch_no' => "0",
|
||||
'show_expire_date' => "0",
|
||||
'show_mfg_date' => "0",
|
||||
'show_product_type_variant' => "0",
|
||||
'show_product_batch_no' => "0",
|
||||
'show_product_expire_date' => "0",
|
||||
'show_product_type_combo' => "0",
|
||||
'show_warehouse' => "0",
|
||||
'show_rack' => "0",
|
||||
'show_shelf' => "0",
|
||||
'show_guarantee' => "0",
|
||||
'show_warranty' => "0",
|
||||
'show_serial' => "0",
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $responseData,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'show_product_name' => 'nullable|integer',
|
||||
'show_product_price' => 'nullable|integer',
|
||||
'show_product_code' => 'nullable|integer',
|
||||
'show_product_stock' => 'nullable|integer',
|
||||
'show_product_sale_price' => 'nullable|integer',
|
||||
'show_product_dealer_price' => 'nullable|integer',
|
||||
'show_product_wholesale_price' => 'nullable|integer',
|
||||
'show_product_unit' => 'nullable|integer',
|
||||
'show_product_brand' => 'nullable|integer',
|
||||
'show_product_category' => 'nullable|integer',
|
||||
'show_product_manufacturer' => 'nullable|integer',
|
||||
'show_product_image' => 'nullable|integer',
|
||||
'show_expire_date' => 'nullable|integer',
|
||||
'show_alert_qty' => 'nullable|integer',
|
||||
'show_vat_id' => 'nullable|integer',
|
||||
'show_vat_type' => 'nullable|integer',
|
||||
'show_exclusive_price' => 'nullable|integer',
|
||||
'show_inclusive_price' => 'nullable|integer',
|
||||
'show_profit_percent' => 'nullable|integer',
|
||||
'show_capacity' => 'nullable|integer',
|
||||
'show_weight' => 'nullable|integer',
|
||||
'show_color' => 'nullable|integer',
|
||||
'show_type' => 'nullable|integer',
|
||||
'show_size' => 'nullable|integer',
|
||||
'show_batch_no' => 'nullable|integer',
|
||||
'show_mfg_date' => 'nullable|integer',
|
||||
'show_model_no' => 'nullable|integer',
|
||||
'default_sale_price' => 'nullable|integer',
|
||||
'default_wholesale_price' => 'nullable|integer',
|
||||
'default_dealer_price' => 'nullable|integer',
|
||||
'show_product_type_single' => 'nullable|integer',
|
||||
'show_product_type_variant' => 'nullable|integer',
|
||||
'show_product_type_combo' => 'nullable|integer',
|
||||
'show_warehouse' => 'nullable|integer',
|
||||
'show_action' => 'nullable|integer',
|
||||
'show_rack' => 'nullable|integer',
|
||||
'show_shelf' => 'nullable|integer',
|
||||
'show_guarantee' => 'nullable|integer',
|
||||
'show_warranty' => 'nullable|integer',
|
||||
'show_serial' => 'nullable|integer',
|
||||
'default_batch_no' => 'nullable|integer',
|
||||
'default_expired_date' => 'nullable|integer',
|
||||
'default_mfg_date' => 'nullable|integer',
|
||||
'expire_date_type' => 'nullable|integer',
|
||||
'mfg_date_type' => 'nullable|integer',
|
||||
'show_product_batch_no' => 'nullable|integer',
|
||||
'show_product_expire_date' => 'nullable|integer'
|
||||
]);
|
||||
|
||||
ProductSetting::updateOrCreate(
|
||||
['business_id' => auth()->user()->business_id],
|
||||
['modules' => $request->all()]
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
416
app/Http/Controllers/Api/PurchaseController.php
Normal file
416
app/Http/Controllers/Api/PurchaseController.php
Normal file
@@ -0,0 +1,416 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Events\MultiPaymentProcessed;
|
||||
use App\Events\PurchaseSms;
|
||||
use App\Models\Party;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\Product;
|
||||
use App\Models\Stock;
|
||||
use App\Models\Purchase;
|
||||
use App\Models\Transaction;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\PurchaseDetails;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\PurchaseReturn;
|
||||
|
||||
class PurchaseController extends Controller
|
||||
{
|
||||
Use DateFilterTrait;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
// Build the query with all eager loads
|
||||
$query = Purchase::with(['user:id,name,role', 'party:id,name,email,phone,type,address', 'details', 'details.product:id,productName,category_id,product_type,vat_id,vat_type,vat_amount', 'details.stock:id,batch_no,variant_name,warehouse_id', 'details.product.vat:id,name,rate', 'details.product.category:id,categoryName', 'purchaseReturns.details', 'vat:id,name,rate', 'branch:id,name,phone,address','transactions:id,platform,transaction_type,amount,date,invoice_no,reference_id,payment_type_id,meta', 'transactions.paymentType:id,name'])->where('business_id', $business_id);
|
||||
|
||||
// Filter returned sales (safer boolean check)
|
||||
$query->when(request('returned-purchase') == "true", function ($query) {
|
||||
$query->whereHas('purchaseReturns');
|
||||
});
|
||||
|
||||
if ($request->filled('branch_id')) {
|
||||
$query->where('branch_id', $request->branch_id);
|
||||
}
|
||||
|
||||
// Apply date filter
|
||||
if(request('duration')){
|
||||
$this->applyDateFilter($query, request('duration'), 'purchaseDate', request('from_date'), request('to_date'));
|
||||
}
|
||||
|
||||
// Search filter
|
||||
if ($request->filled('search')) {
|
||||
$query->where(function ($q) use ($request) {
|
||||
$q->where('paymentType', 'like', "%{$request->search}%")
|
||||
->orWhere('invoiceNumber', 'like', "%{$request->search}%")
|
||||
->orWhereHas('party', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
})
|
||||
->orWhereHas('payment_type', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
})
|
||||
->orWhereHas('branch', function ($q) use ($request) {
|
||||
$q->where('name', 'like', '%' . $request->search . '%');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Finally fetch the data (preserves original structure)
|
||||
$data = $query->latest()->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'total_amount' => $data->sum('totalAmount'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$purchase = Purchase::with(['user:id,name,role', 'party:id,name,email,phone,type,address', 'details', 'details.product:id,productName,category_id,product_type,vat_id,vat_type,vat_amount', 'details.stock:id,batch_no,variant_name,warehouse_id', 'details.product.vat:id,name,rate', 'details.product.category:id,categoryName', 'purchaseReturns.details', 'vat:id,name,rate', 'branch:id,name,phone,address','transactions:id,platform,transaction_type,amount,date,invoice_no,reference_id,payment_type_id,meta', 'transactions.paymentType:id,name'])
|
||||
->where('business_id', $business_id)
|
||||
->where('id', $id)
|
||||
->first();
|
||||
|
||||
if (!$purchase) {
|
||||
return response()->json([
|
||||
'message' => __('Purchase not found.'),
|
||||
], 404);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Purchase fetched successfully.'),
|
||||
'data' => $purchase,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'products' => 'required|array',
|
||||
'products.*.product_id' => 'required|exists:products,id',
|
||||
'party_id' => 'required|exists:parties,id'
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
// Party due update
|
||||
if ($request->dueAmount > 0) {
|
||||
$party = Party::findOrFail($request->party_id);
|
||||
|
||||
// Check party credit limit
|
||||
$newTotalDue = $party->due + $request->dueAmount;
|
||||
if ($party->credit_limit > 0 && $newTotalDue > $party->credit_limit) {
|
||||
return response()->json([
|
||||
'message' => __('Cannot create purchase. Party due will exceed credit limit!')
|
||||
], 400);
|
||||
}
|
||||
|
||||
$party->update([
|
||||
'due' => $newTotalDue
|
||||
]);
|
||||
}
|
||||
|
||||
updateBalance($request->paidAmount, 'decrement');
|
||||
|
||||
$purchase = Purchase::create($request->all() + [
|
||||
'user_id' => auth()->id(),
|
||||
'business_id' => $business_id,
|
||||
]);
|
||||
|
||||
$purchaseDetails = [];
|
||||
foreach ($request->products as $key => $product_data) {
|
||||
|
||||
$batch_no = $product_data['batch_no'] ?? NULL;
|
||||
$variantName = $product_data['variant_name'] ?? null;
|
||||
$existingStock = Stock::where(['batch_no' => $batch_no, 'product_id' => $product_data['product_id']])
|
||||
->when($variantName, fn($q) => $q->where('variant_name', $variantName))
|
||||
->first();
|
||||
|
||||
// update or create stock
|
||||
$stock = Stock::updateOrCreate(
|
||||
[
|
||||
'batch_no' => $batch_no,
|
||||
'business_id' => $business_id,
|
||||
'product_id' => $product_data['product_id'],
|
||||
'variant_name' => $variantName
|
||||
],
|
||||
[
|
||||
'product_id' => $product_data['product_id'],
|
||||
'mfg_date' => $product_data['mfg_date'] ?? NULL,
|
||||
'expire_date' => $product_data['expire_date'] ?? NULL,
|
||||
'profit_percent' => $product_data['profit_percent'] ?? 0,
|
||||
'productSalePrice' => $product_data['productSalePrice'] ?? 0,
|
||||
'productDealerPrice' => $product_data['productDealerPrice'] ?? 0,
|
||||
'productPurchasePrice' => $product_data['productPurchasePrice'] ?? 0,
|
||||
'productWholeSalePrice' => $product_data['productWholeSalePrice'] ?? 0,
|
||||
'productStock' => ($product_data['quantities'] ?? 0) + ($existingStock->productStock ?? 0),
|
||||
'warehouse_id' => $product_data['warehouse_id'] ?? null,
|
||||
]
|
||||
);
|
||||
|
||||
$purchaseDetails[$key] = [
|
||||
'stock_id' => $stock->id,
|
||||
'purchase_id' => $purchase->id,
|
||||
'product_id' => $product_data['product_id'],
|
||||
'quantities' => $product_data['quantities'] ?? 0,
|
||||
'productSalePrice' => $product_data['productSalePrice'] ?? 0,
|
||||
'productDealerPrice' => $product_data['productDealerPrice'] ?? 0,
|
||||
'productPurchasePrice' => $product_data['productPurchasePrice'] ?? 0,
|
||||
'productWholeSalePrice' => $product_data['productWholeSalePrice'] ?? 0,
|
||||
'profit_percent' => $product_data['profit_percent'] ?? 0,
|
||||
'expire_date' => $product_data['expire_date'] ?? NULL,
|
||||
'mfg_date' => $product_data['mfg_date'] ?? NULL,
|
||||
];
|
||||
}
|
||||
|
||||
PurchaseDetails::insert($purchaseDetails);
|
||||
|
||||
// MultiPaymentProcessed Event
|
||||
event(new MultiPaymentProcessed(
|
||||
$request->payments ?? [],
|
||||
$purchase->id,
|
||||
'purchase',
|
||||
$request->paidAmount ?? 0,
|
||||
$request->party_id ?? null,
|
||||
));
|
||||
|
||||
// Send SMS
|
||||
event(new PurchaseSms($purchase));
|
||||
|
||||
DB::commit();
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $purchase->load('user:id,name,role', 'party:id,name,email,phone,type,address', 'details', 'details.stock:id,batch_no', 'details.product:id,productName,category_id,product_type', 'details.product.category:id,categoryName', 'purchaseReturns.details', 'vat:id,name,rate', 'payment_type:id,name', 'branch:id,name,phone,address'),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json(['message' => $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, Purchase $purchase)
|
||||
{
|
||||
$request->validate([
|
||||
'products' => 'required|array',
|
||||
'products.*.product_id' => 'required|exists:products,id',
|
||||
'party_id' => 'required|exists:parties,id'
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
|
||||
$has_return = PurchaseReturn::where('purchase_id', $purchase->id)->count();
|
||||
|
||||
if ($has_return > 0) {
|
||||
return response()->json([
|
||||
'message' => __("You can not update this purchase because it has already been returned.")
|
||||
], 400);
|
||||
}
|
||||
|
||||
// Revert previous stock changes
|
||||
foreach ($purchase->details as $detail) {
|
||||
Stock::where('id', $detail->stock_id)->decrement('productStock', $detail->quantities);
|
||||
}
|
||||
|
||||
// Delete existing purchase details
|
||||
$purchase->details()->delete();
|
||||
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
$purchaseDetails = [];
|
||||
foreach ($request->products as $key => $product_data) {
|
||||
|
||||
$batch_no = $product_data['batch_no'] ?? NULL;
|
||||
$variantName = $cartItem->options['variant_name'] ?? null;
|
||||
$existingStock = Stock::where(['batch_no' => $batch_no, 'product_id' => $product_data['product_id']])
|
||||
->when($variantName, fn($q) => $q->where('variant_name', $variantName))
|
||||
->first();
|
||||
|
||||
// update or create stock
|
||||
$stock = Stock::updateOrCreate(
|
||||
[
|
||||
'batch_no' => $batch_no,
|
||||
'business_id' => $business_id,
|
||||
'product_id' => $product_data['product_id'],
|
||||
'variant_name' => $variantName
|
||||
],
|
||||
[
|
||||
'product_id' => $product_data['product_id'],
|
||||
'mfg_date' => $product_data['mfg_date'] ?? NULL,
|
||||
'expire_date' => $product_data['expire_date'] ?? NULL,
|
||||
'profit_percent' => $product_data['profit_percent'] ?? 0,
|
||||
'productSalePrice' => $product_data['productSalePrice'] ?? 0,
|
||||
'productDealerPrice' => $product_data['productDealerPrice'] ?? 0,
|
||||
'productPurchasePrice' => $product_data['productPurchasePrice'] ?? 0,
|
||||
'productWholeSalePrice' => $product_data['productWholeSalePrice'] ?? 0,
|
||||
'productStock' => ($product_data['quantities'] ?? 0) + ($existingStock->productStock ?? 0),
|
||||
'warehouse_id' => $product_data['warehouse_id'] ?? null,
|
||||
]
|
||||
);
|
||||
|
||||
$purchaseDetails[$key] = [
|
||||
'stock_id' => $stock->id,
|
||||
'purchase_id' => $purchase->id,
|
||||
'product_id' => $product_data['product_id'],
|
||||
'quantities' => $product_data['quantities'] ?? 0,
|
||||
'productSalePrice' => $product_data['productSalePrice'] ?? 0,
|
||||
'productDealerPrice' => $product_data['productDealerPrice'] ?? 0,
|
||||
'productPurchasePrice' => $product_data['productPurchasePrice'] ?? 0,
|
||||
'productWholeSalePrice' => $product_data['productWholeSalePrice'] ?? 0,
|
||||
'profit_percent' => $product_data['profit_percent'] ?? 0,
|
||||
'expire_date' => $product_data['expire_date'] ?? NULL,
|
||||
'mfg_date' => $product_data['mfg_date'] ?? NULL,
|
||||
];
|
||||
}
|
||||
|
||||
PurchaseDetails::insert($purchaseDetails);
|
||||
|
||||
if ($purchase->dueAmount || $request->dueAmount) {
|
||||
$party = Party::findOrFail($request->party_id);
|
||||
|
||||
// Calculate new due for this party
|
||||
$newDue = $request->party_id == $purchase->party_id ? (($party->due - $purchase->dueAmount) + $request->dueAmount) : ($party->due + $request->dueAmount);
|
||||
|
||||
// Check credit limit
|
||||
if ($party->credit_limit > 0 && $newDue > $party->credit_limit) {
|
||||
return response()->json([
|
||||
'message' => __('Cannot update purchase. Party due will exceed credit limit!')
|
||||
], 400);
|
||||
}
|
||||
|
||||
$party->update([
|
||||
'due' => $newDue
|
||||
]);
|
||||
|
||||
// If changed to a new party, reduce previous party’s due
|
||||
if ($request->party_id != $purchase->party_id) {
|
||||
$prev_party = Party::findOrFail($purchase->party_id);
|
||||
$prev_party->update([
|
||||
'due' => $prev_party->due - $purchase->dueAmount
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$balanceDiff = ($purchase->paidAmount ?? 0) - $request->paidAmount;
|
||||
updateBalance($balanceDiff, 'decrement');
|
||||
|
||||
$purchase->update($request->all() + [
|
||||
'user_id' => auth()->id(),
|
||||
]);
|
||||
|
||||
// Multiple Payment Process
|
||||
$oldTransactions = Transaction::where('business_id', $business_id)
|
||||
->where('reference_id', $purchase->id)
|
||||
->where('platform', 'purchase')
|
||||
->get();
|
||||
|
||||
// Revert old transactions
|
||||
foreach ($oldTransactions as $old) {
|
||||
switch ($old->transaction_type) {
|
||||
case 'bank_payment':
|
||||
$paymentType = PaymentType::find($old->payment_type_id);
|
||||
if ($paymentType) {
|
||||
$paymentType->increment('balance', $old->amount);
|
||||
}
|
||||
break;
|
||||
case 'wallet_payment':
|
||||
if ($request->party_id) {
|
||||
$party = Party::find($request->party_id);
|
||||
if ($party) {
|
||||
$party->decrement('wallet', $old->amount);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'cash_payment':
|
||||
case 'cheque_payment':
|
||||
// nothing to revert
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete old transactions
|
||||
Transaction::where('business_id', $business_id)
|
||||
->where('reference_id', $purchase->id)
|
||||
->where('platform', 'purchase')
|
||||
->delete();
|
||||
|
||||
event(new MultiPaymentProcessed(
|
||||
$request->payments ?? [],
|
||||
$purchase->id,
|
||||
'purchase',
|
||||
$request->paidAmount ?? 0,
|
||||
$request->party_id ?? null,
|
||||
));
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $purchase->load('user:id,name,role', 'party:id,name,email,phone,type,address', 'details', 'details.stock:id,batch_no', 'details.product:id,productName,category_id,product_type', 'details.product.category:id,categoryName', 'purchaseReturns.details', 'vat:id,name,rate', 'payment_type:id,name'),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json(['message' => $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(string $id)
|
||||
{
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$purchase = Purchase::with('details')->findOrFail($id);
|
||||
|
||||
$has_return = PurchaseReturn::where('purchase_id', $purchase->id)->count();
|
||||
|
||||
if ($has_return > 0) {
|
||||
return response()->json([
|
||||
'message' => __("You can not update this purchase because it has already been returned.")
|
||||
], 400);
|
||||
}
|
||||
|
||||
if ($purchase->dueAmount) {
|
||||
$party = Party::findOrFail($purchase->party_id);
|
||||
$party->update([
|
||||
'due' => $party->due - $purchase->dueAmount
|
||||
]);
|
||||
}
|
||||
|
||||
foreach ($purchase->details as $detail) {
|
||||
Stock::where('id', $detail->stock_id)->decrement('productStock', $detail->quantities);
|
||||
}
|
||||
|
||||
updateBalance($purchase->paidAmount, 'increment');
|
||||
|
||||
sendNotifyToUser($purchase->id, route('business.purchases.index', ['id' => $purchase->id]), __('Purchase has been deleted.'), $purchase->business_id);
|
||||
|
||||
$purchase->delete();
|
||||
|
||||
DB::commit();
|
||||
return response()->json([
|
||||
'message' => __('Data deleted successfully.'),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json(['message' => $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
188
app/Http/Controllers/Api/PurchaseReturnController.php
Normal file
188
app/Http/Controllers/Api/PurchaseReturnController.php
Normal file
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Events\MultiPaymentProcessed;
|
||||
use App\Models\Party;
|
||||
use App\Models\Stock;
|
||||
use App\Models\Purchase;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\PurchaseReturn;
|
||||
use App\Models\PurchaseDetails;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\PurchaseReturnDetail;
|
||||
|
||||
class PurchaseReturnController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$data = PurchaseReturn::with('purchase:id,party_id,isPaid,totalAmount,dueAmount,paidAmount,invoiceNumber', 'purchase.party:id,name', 'details')
|
||||
->whereBetween('return_date', [request()->start_date, request()->end_date])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'purchase_id' => 'required|exists:purchases,id',
|
||||
'return_qty' => 'required|array',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$purchase = Purchase::with('details')
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->findOrFail($request->purchase_id);
|
||||
|
||||
// Calculate total discount factor
|
||||
$total_discount = $purchase->discountAmount;
|
||||
$total_purchase_amount = $purchase->details->sum(fn($detail) => $detail->productPurchasePrice * $detail->quantities);
|
||||
$discount_per_unit_factor = $total_purchase_amount > 0 ? $total_discount / $total_purchase_amount : 0;
|
||||
|
||||
$purchase_return = PurchaseReturn::create([
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'purchase_id' => $request->purchase_id,
|
||||
'invoice_no' => $purchase->invoiceNumber,
|
||||
'return_date' => now(),
|
||||
]);
|
||||
|
||||
$purchase_return_detail_data = [];
|
||||
$total_return_amount = 0;
|
||||
$total_return_discount = 0;
|
||||
|
||||
// Loop through each purchase detail and process the return
|
||||
foreach ($purchase->details as $key => $detail) {
|
||||
$requested_qty = $request->return_qty[$key];
|
||||
|
||||
if ($requested_qty <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if return quantity exceeds the purchased quantity
|
||||
if ($requested_qty > $detail->quantities) {
|
||||
return response()->json([
|
||||
'message' => "You can't return more than the ordered quantity of {$detail->quantities}.",
|
||||
], 400);
|
||||
}
|
||||
|
||||
// Calculate per-unit discount and return amounts
|
||||
$unit_discount = $detail->productPurchasePrice * $discount_per_unit_factor;
|
||||
$return_discount = $unit_discount * $requested_qty;
|
||||
$return_amount = ($detail->productPurchasePrice - $unit_discount) * $requested_qty;
|
||||
|
||||
$total_return_amount += $return_amount;
|
||||
$total_return_discount += $return_discount;
|
||||
|
||||
// Update stock & purchase details
|
||||
Stock::where('id', $detail->stock_id)->decrement('productStock', $requested_qty);
|
||||
|
||||
$detail->quantities -= $requested_qty;
|
||||
$detail->timestamps = false;
|
||||
$detail->save();
|
||||
|
||||
// Collect return detail data
|
||||
$purchase_return_detail_data[] = [
|
||||
'purchase_detail_id' => $detail->id,
|
||||
'purchase_return_id' => $purchase_return->id,
|
||||
'return_qty' => $requested_qty,
|
||||
'business_id' => auth()->user()->business_id,
|
||||
'return_amount' => $return_amount,
|
||||
];
|
||||
}
|
||||
|
||||
// Insert purchase return details
|
||||
if (!empty($purchase_return_detail_data)) {
|
||||
PurchaseReturnDetail::insert($purchase_return_detail_data);
|
||||
}
|
||||
|
||||
if ($total_return_amount <= 0) {
|
||||
return response()->json("You cannot return an empty product.", 400);
|
||||
}
|
||||
|
||||
// Update party dues (if applicable)
|
||||
$party = Party::find($purchase->party_id);
|
||||
|
||||
if ($party) {
|
||||
$refund_amount = $total_return_amount;
|
||||
|
||||
// If party has due, reduce it first
|
||||
if ($party->due > 0) {
|
||||
if ($party->due >= $refund_amount) {
|
||||
$party->decrement('due', $refund_amount);
|
||||
$refund_amount = 0;
|
||||
} else {
|
||||
$refund_amount -= $party->due;
|
||||
$party->update(['due' => 0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Any remaining amount should be deducted from wallet
|
||||
if ($refund_amount > 0 && $party->wallet > 0) {
|
||||
$deduct = min($party->wallet, $refund_amount);
|
||||
$party->decrement('wallet', $deduct);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate remaining return amount
|
||||
$remaining_return_amount = max(0, $total_return_amount - $purchase->dueAmount);
|
||||
$new_total_amount = max(0, $purchase->totalAmount - $total_return_amount);
|
||||
|
||||
// Update purchase record
|
||||
$purchase->update([
|
||||
'change_amount' => 0,
|
||||
'dueAmount' => max(0, $purchase->dueAmount - $total_return_amount),
|
||||
'paidAmount' => max(0, $purchase->paidAmount - min($purchase->paidAmount, $total_return_amount)),
|
||||
'totalAmount' => $new_total_amount,
|
||||
'discountAmount' => max(0, $purchase->discountAmount - $total_return_discount),
|
||||
'isPaid' => $remaining_return_amount > 0 ? 1 : $purchase->isPaid,
|
||||
]);
|
||||
|
||||
$payments = $request->payments ?? [];
|
||||
$payments = collect($payments)->map(function ($payment) use ($total_return_amount) {
|
||||
$payment['amount'] = $total_return_amount;
|
||||
return $payment;
|
||||
})->toArray();
|
||||
|
||||
event(new MultiPaymentProcessed(
|
||||
$payments,
|
||||
$purchase_return->id,
|
||||
'purchase_return',
|
||||
$total_return_amount ?? 0,
|
||||
));
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $purchase_return,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json(['error' => 'Transaction failed: ' . $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
{
|
||||
$data = PurchaseReturn::with('purchase:id,party_id,isPaid,totalAmount,dueAmount,paidAmount,invoiceNumber', 'purchase.party:id,name', 'details')->findOrFail($id);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
}
|
||||
87
app/Http/Controllers/Api/RackController.php
Normal file
87
app/Http/Controllers/Api/RackController.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Rack;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class RackController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$data = Rack::with('shelves:id,name')->where('business_id', auth()->user()->business_id)->latest()->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'shelf_id' => 'required|array',
|
||||
'shelf_id.*' => 'exists:shelves,id',
|
||||
'name' => 'required|string|max:255',
|
||||
'status' => 'required|in:0,1',
|
||||
]);
|
||||
|
||||
$rack = Rack::create($request->except('business_id') + [
|
||||
'business_id' => auth()->user()->business_id
|
||||
]);
|
||||
|
||||
$rack->shelves()->sync($request->shelf_id);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $rack,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
$rack = Rack::find($id);
|
||||
if (!$rack) {
|
||||
return response()->json([
|
||||
'message' => __('Rack not found.'),
|
||||
'data' => null,
|
||||
], 404);
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
'shelf_id' => 'required|array',
|
||||
'shelf_id.*' => 'exists:shelves,id',
|
||||
'name' => 'required|string|max:255',
|
||||
'status' => 'required|in:0,1',
|
||||
]);
|
||||
|
||||
$rack->update($request->except('business_id') + [
|
||||
'business_id' => auth()->user()->business_id
|
||||
]);
|
||||
|
||||
$rack->shelves()->sync($request->shelf_id);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data updated successfully.'),
|
||||
'data' => $rack,
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(string $id)
|
||||
{
|
||||
$rack = Rack::find($id);
|
||||
|
||||
if (!$rack) {
|
||||
return response()->json([
|
||||
'message' => __('Rack not found.'),
|
||||
], 404);
|
||||
}
|
||||
|
||||
$rack->delete();
|
||||
return response()->json([
|
||||
'message' => __('Data deleted successfully.'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
255
app/Http/Controllers/Api/SaleReturnController.php
Normal file
255
app/Http/Controllers/Api/SaleReturnController.php
Normal file
@@ -0,0 +1,255 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Events\MultiPaymentProcessed;
|
||||
use App\Models\Sale;
|
||||
use App\Models\Party;
|
||||
use App\Models\Stock;
|
||||
use App\Models\SaleReturn;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\SaleReturnDetails;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class SaleReturnController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$data = SaleReturn::with('sale:id,party_id,isPaid,totalAmount,dueAmount,paidAmount,invoiceNumber', 'sale.party:id,name', 'details')
|
||||
->whereBetween('return_date', [request()->start_date, request()->end_date])
|
||||
->where('business_id', auth()->user()->business_id)
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'sale_id' => 'required|exists:sales,id',
|
||||
'return_qty' => 'required|array',
|
||||
]);
|
||||
|
||||
$business_id = auth()->user()->business_id;
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$sale = Sale::with('details:id,sale_id,product_id,price,discount,lossProfit,quantities,productPurchasePrice,stock_id,expire_date', 'details.product:id,product_type', 'details.product.combo_products')
|
||||
->where('business_id', $business_id)
|
||||
->findOrFail($request->sale_id);
|
||||
|
||||
// Calculate total discount factor with itemwise discount
|
||||
$total_discount = $sale->discountAmount;
|
||||
$total_sale_amount = $sale->details->sum(fn($detail) => $detail->price * $detail->quantities);
|
||||
$discount_per_unit_factor = $total_sale_amount > 0 ? $total_discount / $total_sale_amount : 0;
|
||||
$rounding_amount_per_unit = $sale->details->sum('quantities') > 0 ? $sale->rounding_amount / $sale->details->sum('quantities') : 0;
|
||||
|
||||
$sale_return = SaleReturn::create([
|
||||
'business_id' => $business_id,
|
||||
'sale_id' => $request->sale_id,
|
||||
'invoice_no' => $sale->invoiceNumber,
|
||||
'return_date' => now(),
|
||||
]);
|
||||
|
||||
$sale_return_detail_data = [];
|
||||
$total_return_amount = 0;
|
||||
$total_return_discount = 0;
|
||||
$total_loss_profit_adjustment = 0;
|
||||
|
||||
foreach ($sale->details as $key => $detail) {
|
||||
$requested_qty = $request->return_qty[$key];
|
||||
|
||||
if ($requested_qty <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($requested_qty > $detail->quantities) {
|
||||
return response()->json([
|
||||
'message' => "You can't return more than ordered quantity of {$detail->quantities}.",
|
||||
], 400);
|
||||
}
|
||||
|
||||
$product = $detail->product;
|
||||
|
||||
// Include SaleDetails discount in return calculation
|
||||
$unit_discount = $detail->price * $discount_per_unit_factor;
|
||||
$item_cart_discount = $detail->discount ?? 0;
|
||||
$total_discount_per_unit = $unit_discount + $item_cart_discount;
|
||||
|
||||
$return_discount = $total_discount_per_unit * $requested_qty;
|
||||
$return_amount = ($detail->price - $total_discount_per_unit + $rounding_amount_per_unit) * $requested_qty;
|
||||
|
||||
$total_return_amount += $return_amount;
|
||||
$total_return_discount += $return_discount;
|
||||
|
||||
if ($product && $product->product_type === 'combo') {
|
||||
|
||||
$combo_total_purchase = 0;
|
||||
$combo_total_sale = $detail->price * $requested_qty;
|
||||
|
||||
foreach ($product->combo_products as $comboItem) {
|
||||
$stock = Stock::find($comboItem->stock_id);
|
||||
|
||||
if (!$stock) {
|
||||
return response()->json([
|
||||
'message' => __("Stock not found for combo item '{$comboItem->product->productName}'"),
|
||||
], 400);
|
||||
}
|
||||
|
||||
// increase stock by combo component quantity * returned qty
|
||||
$restore_qty = $comboItem->quantity * $requested_qty;
|
||||
$stock->increment('productStock', $restore_qty);
|
||||
|
||||
$combo_total_purchase += $comboItem->purchase_price * $restore_qty;
|
||||
}
|
||||
|
||||
// loss/profit adjustment for combo
|
||||
$loss_profit_adjustment = ($combo_total_sale - $combo_total_purchase) - $return_discount;
|
||||
$total_loss_profit_adjustment += $loss_profit_adjustment;
|
||||
}
|
||||
|
||||
else {
|
||||
$stock = Stock::where('id', $detail->stock_id)->first();
|
||||
if (!$stock) {
|
||||
return response()->json(['error' => 'Stock not found.'], 404);
|
||||
}
|
||||
|
||||
$stock->increment('productStock', $requested_qty);
|
||||
|
||||
$loss_profit_adjustment = (($detail->price - $stock->productPurchasePrice) * $requested_qty) - $return_discount;
|
||||
$total_loss_profit_adjustment += $loss_profit_adjustment;
|
||||
}
|
||||
|
||||
// Update sale details
|
||||
$detail->quantities -= $requested_qty;
|
||||
$detail->lossProfit -= $loss_profit_adjustment;
|
||||
$detail->timestamps = false;
|
||||
$detail->save();
|
||||
|
||||
$sale_return_detail_data[] = [
|
||||
'business_id' => $business_id,
|
||||
'sale_detail_id' => $detail->id,
|
||||
'sale_return_id' => $sale_return->id,
|
||||
'return_qty' => $requested_qty,
|
||||
'return_amount' => $return_amount,
|
||||
];
|
||||
}
|
||||
|
||||
if (!empty($sale_return_detail_data)) {
|
||||
SaleReturnDetails::insert($sale_return_detail_data);
|
||||
}
|
||||
|
||||
if ($total_return_amount <= 0) {
|
||||
return response()->json("You cannot return an empty product.", 400);
|
||||
}
|
||||
|
||||
$remaining_refund = $total_return_amount;
|
||||
|
||||
// Adjust Due
|
||||
$new_due = $sale->dueAmount;
|
||||
if ($remaining_refund > 0) {
|
||||
if ($remaining_refund >= $sale->dueAmount) {
|
||||
$remaining_refund -= $sale->dueAmount;
|
||||
$new_due = 0;
|
||||
} else {
|
||||
$new_due = $sale->dueAmount - $remaining_refund;
|
||||
$remaining_refund = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust Paid (refund part)
|
||||
$new_paid = $sale->paidAmount;
|
||||
if ($remaining_refund > 0) {
|
||||
if ($remaining_refund >= $sale->paidAmount) {
|
||||
$remaining_refund -= $sale->paidAmount;
|
||||
$new_paid = 0;
|
||||
} else {
|
||||
$new_paid = $sale->paidAmount - $remaining_refund;
|
||||
$remaining_refund = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// total sale amount
|
||||
$new_total_amount = max(0, $sale->totalAmount - $total_return_amount);
|
||||
|
||||
$sale->update([
|
||||
'change_amount' => 0,
|
||||
'dueAmount' => $new_due,
|
||||
'paidAmount' => $new_paid,
|
||||
'totalAmount' => $new_total_amount,
|
||||
'actual_total_amount' => $new_total_amount,
|
||||
'discountAmount' => max(0, $sale->discountAmount - $total_return_discount),
|
||||
'lossProfit' => $sale->lossProfit - $total_loss_profit_adjustment,
|
||||
]);
|
||||
|
||||
// Party Refund Logic
|
||||
$party = Party::find($sale->party_id);
|
||||
|
||||
if ($party) {
|
||||
|
||||
// use leftover refund after due/paid adjustments
|
||||
$refund_amount = $remaining_refund;
|
||||
|
||||
// Reduce party due
|
||||
if ($party->due > 0) {
|
||||
if ($party->due >= $refund_amount) {
|
||||
$party->decrement('due', $refund_amount);
|
||||
$refund_amount = 0;
|
||||
} else {
|
||||
$refund_amount -= $party->due;
|
||||
$party->update(['due' => 0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Add leftover refund to wallet
|
||||
if ($refund_amount > 0) {
|
||||
$party->increment('wallet', $refund_amount);
|
||||
}
|
||||
}
|
||||
|
||||
$payments = $request->payments ?? [];
|
||||
$payments = collect($payments)->map(function ($payment) use ($total_return_amount) {
|
||||
$payment['amount'] = $total_return_amount;
|
||||
return $payment;
|
||||
})->toArray();
|
||||
|
||||
event(new MultiPaymentProcessed(
|
||||
$payments,
|
||||
$sale_return->id,
|
||||
'sale_return',
|
||||
$total_return_amount ?? 0,
|
||||
));
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $sale_return,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return response()->json(['error' => 'Transaction failed: ' . $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
{
|
||||
$data = SaleReturn::with('sale:id,party_id,isPaid,totalAmount,dueAmount,paidAmount,invoiceNumber', 'sale.party:id,name', 'details')->findOrFail($id);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
}
|
||||
80
app/Http/Controllers/Api/ShelfController.php
Normal file
80
app/Http/Controllers/Api/ShelfController.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Shelf;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class ShelfController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$data = Shelf::where('business_id', auth()->user()->business_id)->latest()->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'status' => 'required|in:0,1',
|
||||
]);
|
||||
|
||||
$shelf = Shelf::create($request->except('business_id') + [
|
||||
'business_id' => auth()->user()->business_id
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $shelf,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
$shelf = Shelf::find($id);
|
||||
|
||||
if (!$shelf) {
|
||||
return response()->json([
|
||||
'message' => __('Shelf not found.'),
|
||||
'data' => null,
|
||||
], 404);
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'status' => 'required|in:0,1',
|
||||
]);
|
||||
|
||||
$shelf->update($request->except('business_id') + [
|
||||
'business_id' => auth()->user()->business_id
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data updated successfully.'),
|
||||
'data' => $shelf,
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(string $id)
|
||||
{
|
||||
$shelf = Shelf::find($id);
|
||||
|
||||
if (!$shelf) {
|
||||
return response()->json([
|
||||
'message' => __('Shelf not found.'),
|
||||
], 404);
|
||||
}
|
||||
|
||||
$shelf->delete();
|
||||
return response()->json([
|
||||
'message' => __('Data deleted successfully.'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
238
app/Http/Controllers/Api/StatisticsController.php
Normal file
238
app/Http/Controllers/Api/StatisticsController.php
Normal file
@@ -0,0 +1,238 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use App\Models\Sale;
|
||||
use App\Models\Income;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Product;
|
||||
use App\Models\Category;
|
||||
use App\Models\Purchase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class StatisticsController extends Controller
|
||||
{
|
||||
public function summary()
|
||||
{
|
||||
$business_id = auth()->user()->business_id;
|
||||
$date = request('date') ?? today();
|
||||
|
||||
$sale_profit = Sale::where('business_id', $business_id)->whereDate('created_at', $date)->where('lossProfit', '>', 0)->sum('lossProfit');
|
||||
|
||||
$data = [
|
||||
'sales' => (float)Sale::where('business_id', $business_id)->whereDate('created_at', $date)->sum('totalAmount'),
|
||||
'income' => (float)Income::where('business_id', $business_id)->whereDate('created_at', $date)->sum('amount') + $sale_profit,
|
||||
'expense' => (float)Expense::where('business_id', $business_id)->whereDate('created_at', $date)->sum('amount'),
|
||||
'purchase' => (float)Purchase::where('business_id', $business_id)->whereDate('created_at', $date)->sum('totalAmount'),
|
||||
];
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function dashboard()
|
||||
{
|
||||
$currentDate = Carbon::now();
|
||||
$business_id = auth()->user()->business_id;
|
||||
$duration = request('duration');
|
||||
|
||||
// Set date range, format, and period based on selected duration
|
||||
switch ($duration) {
|
||||
case 'today':
|
||||
$start = $currentDate->copy()->startOfDay();
|
||||
$end = $currentDate->copy()->endOfDay();
|
||||
$format = 'H';
|
||||
$period = $start->hoursUntil($end);
|
||||
break;
|
||||
|
||||
case 'yesterday':
|
||||
$start = $currentDate->copy()->subDay()->startOfDay();
|
||||
$end = $currentDate->copy()->subDay()->endOfDay();
|
||||
$format = 'H';
|
||||
$period = $start->hoursUntil($end);
|
||||
break;
|
||||
|
||||
case 'last_seven_days':
|
||||
$start = $currentDate->copy()->subDays(6)->startOfDay();
|
||||
$end = $currentDate->copy()->endOfDay();
|
||||
$format = 'd';
|
||||
$period = $start->daysUntil($end);
|
||||
break;
|
||||
|
||||
case 'last_thirty_days':
|
||||
$start = $currentDate->copy()->subDays(29)->startOfDay();
|
||||
$end = $currentDate->copy()->endOfDay();
|
||||
$format = 'd';
|
||||
$period = $start->daysUntil($end);
|
||||
break;
|
||||
|
||||
case 'current_month':
|
||||
$start = $currentDate->copy()->startOfMonth();
|
||||
$end = $currentDate->copy()->endOfMonth();
|
||||
$format = 'd';
|
||||
$period = $start->daysUntil($end);
|
||||
break;
|
||||
|
||||
case 'last_month':
|
||||
$start = $currentDate->copy()->subMonthNoOverflow()->startOfMonth();
|
||||
$end = $currentDate->copy()->subMonthNoOverflow()->endOfMonth();
|
||||
$format = 'd';
|
||||
$period = $start->daysUntil($end);
|
||||
break;
|
||||
|
||||
case 'current_year':
|
||||
$start = $currentDate->copy()->startOfYear();
|
||||
$end = $currentDate->copy()->endOfYear();
|
||||
$format = 'M';
|
||||
$period = $start->monthsUntil($end);
|
||||
break;
|
||||
|
||||
case 'custom_date':
|
||||
if (request()->has('from_date') && request()->has('to_date')) {
|
||||
$start = Carbon::parse(request('from_date'))->startOfDay();
|
||||
$end = Carbon::parse(request('to_date'))->endOfDay();
|
||||
$format = 'd';
|
||||
$period = $start->daysUntil($end);
|
||||
} else {
|
||||
return response()->json(['error' => 'From and To dates are required for custom date.'], 400);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return response()->json(['error' => 'Invalid duration'], 400);
|
||||
}
|
||||
|
||||
// SQL date format for grouping
|
||||
$dateFormatSQL = match ($format) {
|
||||
'H' => '%H',
|
||||
'd' => '%Y-%m-%d',
|
||||
'M' => '%Y-%m',
|
||||
default => '%Y-%m-%d',
|
||||
};
|
||||
|
||||
// Sales data fetch and map
|
||||
$sales_data = Sale::selectRaw("DATE_FORMAT(created_at, '$dateFormatSQL') as date, SUM(totalAmount) as amount")
|
||||
->where('business_id', $business_id)
|
||||
->whereBetween('created_at', [$start, $end])
|
||||
->groupBy('date')
|
||||
->orderBy('date')
|
||||
->get()
|
||||
->map(function ($item) {
|
||||
$item->amount = (float) $item->amount;
|
||||
return $item;
|
||||
})
|
||||
->keyBy('date');
|
||||
|
||||
// Purchase data fetch and map
|
||||
$purchase_data = Purchase::selectRaw("DATE_FORMAT(created_at, '$dateFormatSQL') as date, SUM(totalAmount) as amount")
|
||||
->where('business_id', $business_id)
|
||||
->whereBetween('created_at', [$start, $end])
|
||||
->groupBy('date')
|
||||
->orderBy('date')
|
||||
->get()
|
||||
->map(function ($item) {
|
||||
$item->amount = (float) $item->amount;
|
||||
return $item;
|
||||
})
|
||||
->keyBy('date');
|
||||
|
||||
$income_amount = Income::where('business_id', $business_id)
|
||||
->whereBetween('created_at', [$start, $end])
|
||||
->sum('amount');
|
||||
|
||||
$sale_profit = Sale::where('business_id', $business_id)
|
||||
->whereBetween('created_at', [$start, $end])
|
||||
->where('lossProfit', '>', 0)
|
||||
->sum('lossProfit');
|
||||
|
||||
$expense_amount = Expense::where('business_id', $business_id)
|
||||
->whereBetween('created_at', [$start, $end])
|
||||
->sum('amount');
|
||||
|
||||
$productQuery = Product::select('id', 'business_id', 'productName', 'product_type', 'created_at')
|
||||
->with(['stocks:id,business_id,product_id,productStock,productPurchasePrice', 'combo_products.stock'])
|
||||
->where('business_id', $business_id);
|
||||
|
||||
$total_stock_value = 0;
|
||||
|
||||
$products = $productQuery->get()
|
||||
->map(function ($item) {
|
||||
$item->source = 'product';
|
||||
return $item;
|
||||
});
|
||||
|
||||
foreach ($products as $product) {
|
||||
// SINGLE / VARIANT
|
||||
if (in_array($product->product_type, ['single', 'variant'])) {
|
||||
foreach ($product->stocks as $stock) {
|
||||
$total_stock_value += $stock->productStock * $stock->productPurchasePrice;
|
||||
}
|
||||
}
|
||||
|
||||
// COMBO
|
||||
if ($product->product_type === 'combo') {
|
||||
foreach ($product->combo_products as $combo) {
|
||||
$childStock = $combo->stock;
|
||||
if ($childStock) {
|
||||
$total_stock_value += ($childStock->productStock / $combo->quantity) * $combo->purchase_price;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$data = [
|
||||
'total_expense' => (float) $expense_amount,
|
||||
'total_income' => (float) $income_amount + $sale_profit,
|
||||
'total_items' => Product::where('business_id', $business_id)->count(),
|
||||
'total_categories' => Category::where('business_id', $business_id)->count(),
|
||||
'stock_value' => $total_stock_value,
|
||||
'total_due' => (float) Sale::where('business_id', $business_id)->whereBetween('saleDate', [$start, $end])->sum('dueAmount'),
|
||||
'total_profit' => (float) Sale::where('business_id', $business_id)->whereBetween('created_at', [$start, $end])->where('lossProfit', '>', 0)->sum('lossProfit'),
|
||||
'total_loss' => (float) Sale::where('business_id', $business_id)->whereBetween('created_at', [$start, $end])->where('lossProfit', '<', 0)->sum('lossProfit'),
|
||||
'sales' => $this->formatData($period, $sales_data, $format),
|
||||
'purchases' => $this->formatData($period, $purchase_data, $format),
|
||||
];
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
private function formatData($period, $datas, $format)
|
||||
{
|
||||
$rows = [];
|
||||
|
||||
foreach ($period as $date) {
|
||||
$key = $date->format($format);
|
||||
|
||||
if ($format === 'M') {
|
||||
// Sum amounts for the month
|
||||
$dateKey = $date->format('Y-m');
|
||||
$amount = $datas->filter(fn($value) => strpos($value->date, $dateKey) === 0)->sum('amount');
|
||||
} elseif ($format === 'd') {
|
||||
// Get amount by full date
|
||||
$fullDateKey = $date->format('Y-m-d');
|
||||
$amount = $datas->get($fullDateKey)?->amount ?? 0;
|
||||
} elseif ($format === 'H') {
|
||||
// Get amount by hour
|
||||
$amount = $datas->get($key)?->amount ?? 0;
|
||||
} else {
|
||||
// Default: treat as full date
|
||||
$fullDateKey = $date->format('Y-m-d');
|
||||
$amount = $datas->get($fullDateKey)?->amount ?? 0;
|
||||
}
|
||||
|
||||
$rows[] = [
|
||||
'date' => $key,
|
||||
'amount' => $amount,
|
||||
];
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
}
|
||||
51
app/Http/Controllers/Api/StockController.php
Normal file
51
app/Http/Controllers/Api/StockController.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Stock;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class StockController extends Controller
|
||||
{
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'productStock' => 'required|integer',
|
||||
'stock_id' => 'required|exists:stocks,id'
|
||||
]);
|
||||
|
||||
Stock::where('id', $request->stock_id)->increment('productStock', $request->productStock);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
Stock::where('id', $id)->update($request->except('_method'));
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(string $id)
|
||||
{
|
||||
Stock::where('id', $id)->delete();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data deleted successfully.'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
110
app/Http/Controllers/Api/TransactionController.php
Normal file
110
app/Http/Controllers/Api/TransactionController.php
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Transaction;
|
||||
use App\Traits\DateFilterTrait;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TransactionController extends Controller
|
||||
{
|
||||
use DateFilterTrait;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$businessId = auth()->user()->business_id;
|
||||
|
||||
$transactionsQuery = Transaction::with([
|
||||
'paymentType',
|
||||
'sale.party',
|
||||
'purchase.party',
|
||||
'dueCollect.party'
|
||||
])
|
||||
->where('business_id', $businessId);
|
||||
|
||||
if (request('duration')) {
|
||||
$this->applyDateFilter($transactionsQuery, request('duration'), 'date', request('from_date'), request('to_date'));
|
||||
}
|
||||
|
||||
// Platform filter
|
||||
if (request('platform')) {
|
||||
$transactionsQuery->where('platform', $request->platform);
|
||||
}
|
||||
|
||||
// Party filter
|
||||
if (request('party_id')) {
|
||||
$transactionsQuery->where(function ($q) use ($request) {
|
||||
|
||||
$q->where(function ($saleQ) use ($request) {
|
||||
$saleQ->where('platform', 'sale')
|
||||
->whereHas('sale', fn($s) => $s->where('party_id', $request->party_id)
|
||||
);
|
||||
});
|
||||
|
||||
$q->orWhere(function ($purQ) use ($request) {
|
||||
$purQ->where('platform', 'purchase')
|
||||
->whereHas('purchase', fn($p) => $p->where('party_id', $request->party_id)
|
||||
);
|
||||
});
|
||||
|
||||
$q->orWhere(function ($dueQ) use ($request) {
|
||||
$dueQ->where('platform', 'due_collect')
|
||||
->whereHas('dueCollect', fn($d) => $d->where('party_id', $request->party_id)
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Summary
|
||||
$total_tr_amount = (clone $transactionsQuery)->sum('amount');
|
||||
|
||||
$total_tr_money_in = (clone $transactionsQuery)
|
||||
->where('type', 'credit')
|
||||
->sum('amount');
|
||||
|
||||
$total_tr_money_out = (clone $transactionsQuery)
|
||||
->where('type', 'debit')
|
||||
->sum('amount');
|
||||
|
||||
// No pagination
|
||||
$transactions = $transactionsQuery->latest()->get();
|
||||
|
||||
|
||||
$transactions->transform(function ($transaction) {
|
||||
$transaction->total_amount = match($transaction->platform) {
|
||||
'sale' => $transaction->sale?->totalAmount ?? 0,
|
||||
'purchase' => $transaction->purchase?->totalAmount ?? 0,
|
||||
'due_collect' => $transaction->dueCollect?->totalDue ?? 0,
|
||||
'sale_return' => $transaction->saleReturn?->sale?->totalAmount ?? 0,
|
||||
'purchase_return' => $transaction->purchaseReturn?->purchase?->totalAmount ?? 0,
|
||||
default => 0
|
||||
};
|
||||
|
||||
return $transaction;
|
||||
});
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'total_amount' => $total_tr_amount,
|
||||
'money_in' => $total_tr_money_in,
|
||||
'money_out' => $total_tr_money_out,
|
||||
'data' => $transactions,
|
||||
]);
|
||||
}
|
||||
|
||||
public function moneyReceipt($id)
|
||||
{
|
||||
$transaction = Transaction::with([
|
||||
'paymentType',
|
||||
'sale.party',
|
||||
'purchase.party',
|
||||
'dueCollect.party'
|
||||
])->find($id);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $transaction,
|
||||
]);
|
||||
}
|
||||
}
|
||||
73
app/Http/Controllers/Api/UnitController.php
Normal file
73
app/Http/Controllers/Api/UnitController.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Unit;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class UnitController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$data = Unit::where('business_id', auth()->user()->business_id)->latest()->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'unitName' => 'required|unique:units,unitName,NULL,id,business_id,' . auth()->user()->business_id,
|
||||
]);
|
||||
|
||||
$data = Unit::create($request->all() + [
|
||||
'business_id' => auth()->user()->business_id
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, Unit $unit)
|
||||
{
|
||||
$request->validate([
|
||||
'unitName' => [
|
||||
'required',
|
||||
'unique:units,unitName,' . $unit->id . ',id,business_id,' . auth()->user()->business_id,
|
||||
],
|
||||
]);
|
||||
|
||||
$unit = $unit->update($request->all());
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $unit,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(Unit $unit)
|
||||
{
|
||||
$unit->delete();
|
||||
return response()->json([
|
||||
'message' => __('Data deleted successfully.'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
90
app/Http/Controllers/Api/VariationController.php
Normal file
90
app/Http/Controllers/Api/VariationController.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Variation;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class VariationController extends Controller
|
||||
{
|
||||
|
||||
public function index()
|
||||
{
|
||||
$data = Variation::where('business_id', auth()->user()->business_id)->latest()->get();
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data fetched successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'values' => 'required|string',
|
||||
'status' => 'required|in:0,1',
|
||||
]);
|
||||
|
||||
$valuesArray = array_map('trim', explode(',', $request->values));
|
||||
|
||||
$data = Variation::create([
|
||||
'name' => $request->name,
|
||||
'status' => $request->status,
|
||||
'values' => $valuesArray,
|
||||
'business_id' => auth()->user()->business_id,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data saved successfully.'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
$variation = Variation::find($id);
|
||||
if (!$variation) {
|
||||
return response()->json([
|
||||
'message' => __('Variation not found.'),
|
||||
'data' => null,
|
||||
], 404);
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'values' => 'required|string',
|
||||
'status' => 'required|in:0,1',
|
||||
]);
|
||||
|
||||
$valuesArray = array_map('trim', explode(',', $request->values));
|
||||
|
||||
$variation->update([
|
||||
'name' => $request->name,
|
||||
'status' => $request->status,
|
||||
'values' => $valuesArray,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Data updated successfully.'),
|
||||
'data' => $variation,
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(string $id)
|
||||
{
|
||||
$variation = Variation::find($id);
|
||||
|
||||
if (!$variation) {
|
||||
return response()->json([
|
||||
'message' => __('Variation not found.'),
|
||||
], 404);
|
||||
}
|
||||
|
||||
$variation->delete();
|
||||
return response()->json([
|
||||
'message' => __('Data deleted successfully.'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
146
app/Http/Controllers/Auth/AuthenticatedSessionController.php
Normal file
146
app/Http/Controllers/Auth/AuthenticatedSessionController.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Nwidart\Modules\Facades\Module;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use App\Http\Requests\Auth\LoginRequest;
|
||||
use App\Models\Branch;
|
||||
|
||||
class AuthenticatedSessionController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display the login view.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('auth.login');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming authentication request.
|
||||
*/
|
||||
public function store(LoginRequest $request)
|
||||
{
|
||||
$request->authenticate();
|
||||
|
||||
$request->session()->regenerate();
|
||||
|
||||
$remember = $request->filled('remember') ? 1 : 0;
|
||||
$redirect_url = url('/');
|
||||
$user = auth()->user();
|
||||
|
||||
if ($user->role == 'shop-owner' || $user->role == 'staff') {
|
||||
|
||||
$module = Module::find('Business');
|
||||
|
||||
if ($module) {
|
||||
if ($module->isEnabled()) {
|
||||
|
||||
$business = $user->business;
|
||||
$branch = Branch::find($user->branch_id);
|
||||
|
||||
if ($business && !$business->status) {
|
||||
Auth::logout();
|
||||
return response()->json([
|
||||
'message' => 'Your business is inactive. Please contact your administrator.',
|
||||
'redirect' => route('login')
|
||||
], 406);
|
||||
}
|
||||
|
||||
if (multibranch_active() && branch_count()) {
|
||||
if ($branch && !$branch->status && $user->branch_id && !$branch->is_main) {
|
||||
|
||||
Auth::logout();
|
||||
return response()->json([
|
||||
'message' => 'This branch is not active, Please contact with manager.',
|
||||
'redirect' => route('login'),
|
||||
], 406);
|
||||
}
|
||||
} elseif (!multibranch_active()) {
|
||||
if ($user->active_branch_id) {
|
||||
$user->update([
|
||||
'active_branch_id' => NULL
|
||||
]);
|
||||
} elseif ($user->branch_id && !$branch->is_main) {
|
||||
|
||||
Auth::logout();
|
||||
return response()->json([
|
||||
'message' => 'Multibranch is not allowed in your current package, please upgrade your subscription plan.',
|
||||
'redirect' => route('login'),
|
||||
], 406);
|
||||
}
|
||||
} elseif (!$branch && $user->branch_id) {
|
||||
Auth::logout();
|
||||
return response()->json([
|
||||
'message' => 'Your current branch has been deleted, Please contact with manager.',
|
||||
'redirect' => route('login'),
|
||||
], 406);
|
||||
}
|
||||
|
||||
$redirect_url = route('business.dashboard.index');
|
||||
} else {
|
||||
Auth::logout();
|
||||
return response()->json([
|
||||
'message' => 'Web addon is not active.',
|
||||
'redirect' => route('login'),
|
||||
], 406);
|
||||
}
|
||||
} else {
|
||||
Auth::logout();
|
||||
return response()->json([
|
||||
'message' => 'Web addon is not installed.',
|
||||
'redirect' => route('login'),
|
||||
], 406);
|
||||
}
|
||||
} else if ($user->role == 'affiliator') {
|
||||
|
||||
$module = Module::find('AffiliateAddon');
|
||||
|
||||
if ($module) {
|
||||
if ($module->isEnabled()) {
|
||||
|
||||
$redirect_url = route('business.dashboard.index');
|
||||
} else {
|
||||
Auth::logout();
|
||||
return response()->json([
|
||||
'message' => 'Affiliate addon is not active.',
|
||||
'redirect' => route('login'),
|
||||
], 406);
|
||||
}
|
||||
} else {
|
||||
Auth::logout();
|
||||
return response()->json([
|
||||
'message' => 'affiliate addon is not installed.',
|
||||
'redirect' => route('login'),
|
||||
], 406);
|
||||
}
|
||||
} else {
|
||||
$redirect_url = route('admin.dashboard.index');
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Logged In Successfully'),
|
||||
'remember' => $remember,
|
||||
'redirect' => $redirect_url,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Destroy an authenticated session.
|
||||
*/
|
||||
public function destroy(Request $request): RedirectResponse
|
||||
{
|
||||
Auth::guard('web')->logout();
|
||||
|
||||
$request->session()->invalidate();
|
||||
|
||||
$request->session()->regenerateToken();
|
||||
|
||||
return redirect('/login');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class EmailVerificationNotificationController extends Controller
|
||||
{
|
||||
/**
|
||||
* Send a new email verification notification.
|
||||
*/
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
if ($request->user()->hasVerifiedEmail()) {
|
||||
return redirect()->intended(RouteServiceProvider::HOME);
|
||||
}
|
||||
|
||||
$request->user()->sendEmailVerificationNotification();
|
||||
|
||||
return back()->with('status', 'verification-link-sent');
|
||||
}
|
||||
}
|
||||
82
app/Http/Controllers/Auth/NewPasswordController.php
Normal file
82
app/Http/Controllers/Auth/NewPasswordController.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use Illuminate\View\View;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\Auth\Events\PasswordReset;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class NewPasswordController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display the password reset view.
|
||||
*/
|
||||
public function create(Request $request): View
|
||||
{
|
||||
return view('auth.reset-password', ['request' => $request]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming new password request.
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'token' => ['required'],
|
||||
'email' => ['required', 'email'],
|
||||
'password' => ['required', 'confirmed', 'string'],
|
||||
]);
|
||||
|
||||
// Here we will attempt to reset the user's password. If it is successful we
|
||||
// will update the password on an actual user model and persist it to the
|
||||
// database. Otherwise we will parse the error and return the response.
|
||||
$response = Password::reset(
|
||||
$request->only('email', 'password', 'password_confirmation', 'token'),
|
||||
function ($user) use ($request) {
|
||||
$user->forceFill([
|
||||
'password' => Hash::make($request->password),
|
||||
'remember_token' => Str::random(60),
|
||||
])->save();
|
||||
|
||||
event(new PasswordReset($user));
|
||||
}
|
||||
);
|
||||
|
||||
// If the password was successfully reset, we will redirect the user back to
|
||||
// the application's home authenticated view. If there is an error we can
|
||||
// redirect them back to where they came from with their error message.
|
||||
return $response == Password::PASSWORD_RESET
|
||||
? $this->sendResetLinkResponse($request, $response)
|
||||
: $this->sendResetLinkFailedResponse($request, $response);
|
||||
}
|
||||
|
||||
|
||||
protected function sendResetLinkResponse(Request $request, $response)
|
||||
{
|
||||
return $request->wantsJson()
|
||||
? new JsonResponse(['message' => trans($response), 'redirect' => route('login')])
|
||||
: back()->with('status', trans($response));
|
||||
}
|
||||
|
||||
protected function sendResetLinkFailedResponse(Request $request, $response)
|
||||
{
|
||||
if ($request->wantsJson()) {
|
||||
throw ValidationException::withMessages([
|
||||
'email' => [trans($response)],
|
||||
]);
|
||||
}
|
||||
|
||||
return back()
|
||||
->withInput($request->only('email'))
|
||||
->withErrors(['email' => trans($response)]);
|
||||
}
|
||||
}
|
||||
65
app/Http/Controllers/Auth/PasswordResetLinkController.php
Normal file
65
app/Http/Controllers/Auth/PasswordResetLinkController.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use Illuminate\View\View;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class PasswordResetLinkController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display the password reset link request view.
|
||||
*/
|
||||
public function create(): View
|
||||
{
|
||||
return view('auth.forgot-password');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming password reset link request.
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'email' => ['required', 'email'],
|
||||
]);
|
||||
|
||||
// We will send the password reset link to this user. Once we have attempted
|
||||
// to send the link, we will examine the response then see the message we
|
||||
// need to show to the user. Finally, we'll send out a proper response.
|
||||
$response = Password::sendResetLink(
|
||||
$request->only('email')
|
||||
);
|
||||
|
||||
return $response == Password::RESET_LINK_SENT
|
||||
? $this->sendResetLinkResponse($request, $response)
|
||||
: $this->sendResetLinkFailedResponse($request, $response);
|
||||
}
|
||||
|
||||
protected function sendResetLinkResponse(Request $request, $response)
|
||||
{
|
||||
return $request->wantsJson()
|
||||
? new JsonResponse(trans($response))
|
||||
: back()->with('status', trans($response));
|
||||
}
|
||||
|
||||
protected function sendResetLinkFailedResponse(Request $request, $response)
|
||||
{
|
||||
if ($request->wantsJson()) {
|
||||
throw ValidationException::withMessages([
|
||||
'email' => [trans($response)],
|
||||
]);
|
||||
}
|
||||
|
||||
return back()
|
||||
->withInput($request->only('email'))
|
||||
->withErrors(['email' => trans($response)]);
|
||||
}
|
||||
}
|
||||
299
app/Http/Controllers/Auth/RegisteredUserController.php
Normal file
299
app/Http/Controllers/Auth/RegisteredUserController.php
Normal file
@@ -0,0 +1,299 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Models\Plan;
|
||||
use App\Models\User;
|
||||
use App\Models\Business;
|
||||
use App\Models\Currency;
|
||||
use App\Mail\WelcomeMail;
|
||||
use App\Models\UserCurrency;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\PlanSubscribe;
|
||||
use App\Mail\RegistrationMail;
|
||||
use App\Models\BusinessCategory;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Cookie;
|
||||
use Modules\AffiliateAddon\App\Models\Affiliate;
|
||||
|
||||
class RegisteredUserController extends Controller
|
||||
{
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'email' => 'required|email|max:255',
|
||||
'password' => 'required|max:25|min:4',
|
||||
'plan_id' => 'required|exists:plans,id',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
|
||||
$user = User::where('email', $request->email)->first();
|
||||
|
||||
if (($user ?? false) && $user->is_verified) {
|
||||
return response()->json([
|
||||
'message' => 'This email is already exists.',
|
||||
], 406);
|
||||
}
|
||||
|
||||
if (!$user) {
|
||||
$user = User::create([
|
||||
'email' => $request->email,
|
||||
'password' => Hash::make($request->password),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
$otpSettings = get_option('email-varification');
|
||||
$verify_email = ($otpSettings['otp_status'] ?? 'off') === 'on';
|
||||
|
||||
session()->put('user_id', $user->id);
|
||||
session()->put('plan_id', $request->plan_id);
|
||||
|
||||
if ($verify_email) {
|
||||
// Generate OTP
|
||||
$code = random_int(100000, 999999);
|
||||
$visibility_time = $this->getOtpTimeInSeconds();
|
||||
$expire = now()->addSeconds($visibility_time);
|
||||
|
||||
$user->update([
|
||||
'remember_token' => $code,
|
||||
'email_verified_at' => $expire,
|
||||
]);
|
||||
|
||||
// Send welcome mail
|
||||
if (env('MAIL_USERNAME')) {
|
||||
if (env('QUEUE_MAIL')) {
|
||||
Mail::to($request->email)->queue(new RegistrationMail($code));
|
||||
} else {
|
||||
Mail::to($request->email)->send(new RegistrationMail($code));
|
||||
}
|
||||
} else {
|
||||
return response()->json([
|
||||
'message' => 'Mail service is not configured. Please contact your administrator.',
|
||||
], 406);
|
||||
}
|
||||
} else {
|
||||
$business_categories = BusinessCategory::where('status', 1)->latest()->get();
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => $verify_email ? 'An otp code has been sent to your email. Please check and confirm.' : 'Sign Up completed. Please setup your profile.',
|
||||
'openModal' => true,
|
||||
'email' => $request->email,
|
||||
'business_categories' => $business_categories ?? [],
|
||||
'otp_expiration' => $verify_email ? now()->diffInSeconds($expire) : false,
|
||||
]);
|
||||
} catch (\Throwable $th) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
'message' => 'Something went wrong. Please contact the admin.',
|
||||
], 403);
|
||||
}
|
||||
}
|
||||
|
||||
public function otpResend(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'email' => 'required|email|exists:users,email',
|
||||
]);
|
||||
|
||||
$code = random_int(100000, 999999);
|
||||
$visibility_time = $this->getOtpTimeInSeconds();
|
||||
$expire = now()->addSeconds($visibility_time);
|
||||
|
||||
$data = [
|
||||
'code' => $code,
|
||||
'name' => $request->name,
|
||||
];
|
||||
|
||||
if (env('MAIL_USERNAME')) {
|
||||
if (env('QUEUE_MAIL')) {
|
||||
Mail::to($request->email)->queue(new WelcomeMail($data));
|
||||
} else {
|
||||
Mail::to($request->email)->send(new WelcomeMail($data));
|
||||
}
|
||||
} else {
|
||||
return response()->json([
|
||||
'message' => __('Mail service is not configured. Please contact your administrator.'),
|
||||
], 406);
|
||||
}
|
||||
|
||||
User::where('email', $request->email)->first()->update(['remember_token' => $code, 'email_verified_at' => $expire]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'An otp code has been sent to your email. Please check and confirm.',
|
||||
'otp_expiration' => now()->diffInSeconds($expire),
|
||||
]);
|
||||
}
|
||||
|
||||
public function otpSubmit(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'email' => 'required|email',
|
||||
'otp' => 'required|min:4|max:15',
|
||||
]);
|
||||
|
||||
$user = User::where('email', $request->email)->first();
|
||||
|
||||
if (!$user) {
|
||||
return response()->json(['message' => __('User not found.')], 400);
|
||||
}
|
||||
|
||||
if ($user->remember_token == $request->otp) {
|
||||
if ($user->email_verified_at > now()) {
|
||||
|
||||
$business_categories = BusinessCategory::where('status', 1)->latest()->get();
|
||||
|
||||
$user->update([
|
||||
'is_verified' => 1,
|
||||
'remember_token' => NULL,
|
||||
'email_verified_at' => now(),
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'The otp has been verified successfully!',
|
||||
'business_categories' => $business_categories
|
||||
]);
|
||||
} else {
|
||||
return response()->json(['message' => __('The verification otp has been expired.')], 400);
|
||||
}
|
||||
} else {
|
||||
return response()->json(['message' => __('Invalid otp.')], 400);
|
||||
}
|
||||
}
|
||||
|
||||
public function businessSetup(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'address' => 'nullable|max:250',
|
||||
'companyName' => 'required|max:250',
|
||||
'shopOpeningBalance' => 'nullable|numeric',
|
||||
'business_category_id' => 'required|exists:business_categories,id',
|
||||
'phoneNumber' => 'required|max:20',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
|
||||
$plan = Plan::find(session('plan_id'));
|
||||
$user = User::find(session('user_id'));
|
||||
|
||||
if (!$user) {
|
||||
return response()->json([
|
||||
'message' => 'Something went wrong. Please try again.',
|
||||
'redirect' => route('home'),
|
||||
], 403);
|
||||
}
|
||||
|
||||
if (moduleCheck('AffiliateAddon')) {
|
||||
$refId = null;
|
||||
$refCode = Cookie::get('ref_code');
|
||||
if ($refCode) {
|
||||
$affiliator = Affiliate::where('ref_code', $refCode)->first();
|
||||
if ($affiliator) {
|
||||
$refId = $affiliator->user_id;
|
||||
}
|
||||
}
|
||||
|
||||
$data['affiliator_id'] = $refId;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'address' => $request->address,
|
||||
'companyName' => $request->companyName,
|
||||
'phoneNumber' => $request->phoneNumber,
|
||||
'shopOpeningBalance' => $request->shopOpeningBalance ?? 0,
|
||||
'business_category_id' => $request->business_category_id,
|
||||
];
|
||||
|
||||
$business = Business::create($data);
|
||||
|
||||
$currency = Currency::where('is_default', 1)->first();
|
||||
UserCurrency::create([
|
||||
'name' => $currency->name,
|
||||
'code' => $currency->code,
|
||||
'rate' => $currency->rate,
|
||||
'business_id' => $business->id,
|
||||
'symbol' => $currency->symbol,
|
||||
'currency_id' => $currency->id,
|
||||
'position' => $currency->position,
|
||||
'country_name' => $currency->country_name,
|
||||
]);
|
||||
|
||||
$user->update([
|
||||
'business_id' => $business->id,
|
||||
]);
|
||||
|
||||
if (moduleCheck('Business')) {
|
||||
Auth::login($user);
|
||||
|
||||
$message = 'Your business setup is completed.';
|
||||
$redirect_url = route('business.dashboard.index');
|
||||
} else {
|
||||
$success_modal = true;
|
||||
$message = 'Your business setup is completed. Please download the apk for manage your business.';
|
||||
}
|
||||
|
||||
if ($plan) {
|
||||
|
||||
$plan_price = $plan->offerPrice == 0 && $plan->offerPrice != null ? $plan->offerPrice : $plan->subscriptionPrice;
|
||||
|
||||
if ($plan_price <= 0) {
|
||||
$subscribe = PlanSubscribe::create([
|
||||
'plan_id' => $plan->id,
|
||||
'business_id' => $business->id,
|
||||
'duration' => $plan->duration,
|
||||
'allow_multibranch' => $plan->allow_multibranch
|
||||
]);
|
||||
|
||||
$business->update([
|
||||
'plan_subscribe_id' => $subscribe->id,
|
||||
'subscriptionDate' => $plan ? now() : null,
|
||||
'will_expire' => $plan ? now()->addDays($plan->duration) : null,
|
||||
]);
|
||||
} else {
|
||||
$message = 'Your business setup is completed. Now you are going to the payment page.';
|
||||
$redirect_url = route('payments-gateways.index', ['plan_id' => $plan->id, 'business_id' => $business->id]);
|
||||
}
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'message' => $message,
|
||||
'redirect' => $redirect_url ?? false,
|
||||
'success_modal' => $success_modal ?? false,
|
||||
]);
|
||||
} catch (\Throwable $th) {
|
||||
DB::rollBack();
|
||||
return response()->json([
|
||||
'message' => 'Something went wrong. Please contact the admin.',
|
||||
], 403);
|
||||
}
|
||||
}
|
||||
|
||||
public function getOtpTimeInSeconds()
|
||||
{
|
||||
$otpSettings = get_option('email-varification');
|
||||
|
||||
$time = $otpSettings['otp_expiration_time'] ?? null;
|
||||
$durationType = $otpSettings['otp_duration_type'] ?? 'minute';
|
||||
$defaultFromEnv = env('OTP_VISIBILITY_TIME', 3);
|
||||
|
||||
// Use default if DB value is null
|
||||
if (empty($time)) {
|
||||
return $defaultFromEnv * 60;
|
||||
}
|
||||
|
||||
// Convert minutes to seconds
|
||||
return $durationType == 'minute' ? $time * 60 : $time;
|
||||
}
|
||||
}
|
||||
28
app/Http/Controllers/Auth/VerifyEmailController.php
Normal file
28
app/Http/Controllers/Auth/VerifyEmailController.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Illuminate\Auth\Events\Verified;
|
||||
use Illuminate\Foundation\Auth\EmailVerificationRequest;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
|
||||
class VerifyEmailController extends Controller
|
||||
{
|
||||
/**
|
||||
* Mark the authenticated user's email address as verified.
|
||||
*/
|
||||
public function __invoke(EmailVerificationRequest $request): RedirectResponse
|
||||
{
|
||||
if ($request->user()->hasVerifiedEmail()) {
|
||||
return redirect()->intended(RouteServiceProvider::HOME.'?verified=1');
|
||||
}
|
||||
|
||||
if ($request->user()->markEmailAsVerified()) {
|
||||
event(new Verified($request->user()));
|
||||
}
|
||||
|
||||
return redirect()->intended(RouteServiceProvider::HOME.'?verified=1');
|
||||
}
|
||||
}
|
||||
13
app/Http/Controllers/BkashTokenizePaymentController.php
Normal file
13
app/Http/Controllers/BkashTokenizePaymentController.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class BkashTokenizePaymentController extends Controller
|
||||
{
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
return response()->json(['message' => 'Bkash placeholder']);
|
||||
}
|
||||
}
|
||||
50
app/Http/Controllers/BlogController.php
Normal file
50
app/Http/Controllers/BlogController.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Blog;
|
||||
use App\Models\Option;
|
||||
use App\Models\Comment;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class BlogController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$page_data = get_option('manage-pages');
|
||||
$recent_blogs = Blog::with('user:id,name')->whereStatus(1)->latest()->take(3)->get();
|
||||
$blogs = Blog::with('user:id,name')->whereStatus(1)->take(10)->get();
|
||||
$general = Option::where('key','general')->first();
|
||||
|
||||
return view('web.blog.index', compact('recent_blogs', 'blogs', 'page_data','general'));
|
||||
}
|
||||
|
||||
public function show(string $slug)
|
||||
{
|
||||
$page_data = get_option('manage-pages');
|
||||
$blog = Blog::where('slug', $slug)->firstOrFail();
|
||||
$recent_blogs = Blog::with('user:id,name')->select('id', 'title', 'slug', 'image', 'user_id', 'created_at', 'updated_at')->whereStatus(1)->latest()->limit(3)->get();
|
||||
$comments = Comment::with('blog:id')->whereStatus(1)->where('blog_id', $blog->id)->latest()->limit(3)->get();
|
||||
$general = Option::where('key','general')->first();
|
||||
|
||||
return view('web.blog.show', compact('page_data','blog', 'recent_blogs','comments','general'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'email' => 'required|email',
|
||||
'comment' => 'required|string|max:255',
|
||||
]);
|
||||
|
||||
Comment::create($request->except('blog_id') + [
|
||||
'blog_id' => $request->blog_id,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Your Comment Submitted successfully'),
|
||||
'redirect' => route('blogs.show', $request->blog_slug)
|
||||
]);
|
||||
}
|
||||
}
|
||||
35
app/Http/Controllers/ContactController.php
Normal file
35
app/Http/Controllers/ContactController.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Option;
|
||||
use App\Models\Message;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ContactController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$page_data = get_option('manage-pages');
|
||||
$general = Option::where('key','general')->first();
|
||||
return view('web.contact.index',compact('page_data','general'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'phone' => 'required|string|max:20',
|
||||
'email' => 'required|email|max:255',
|
||||
'company_name' => 'nullable|string|max:255',
|
||||
'message' => 'required|string',
|
||||
]);
|
||||
|
||||
Message::create($request->all());
|
||||
|
||||
return response()->json([
|
||||
'message' => __('Your Message Submitted successfully'),
|
||||
'redirect' => route('contact.index')
|
||||
]);
|
||||
}
|
||||
}
|
||||
257
app/Http/Controllers/Controller.php
Normal file
257
app/Http/Controllers/Controller.php
Normal file
@@ -0,0 +1,257 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
use AuthorizesRequests, ValidatesRequests;
|
||||
protected $message =[
|
||||
//response success ..0
|
||||
[
|
||||
'message'=>'Response Successfully!',
|
||||
'alert-type'=>'success'
|
||||
],
|
||||
//created ..1
|
||||
[
|
||||
'message'=>'Data Created Successfully!',
|
||||
'alert-type'=>'success'
|
||||
],
|
||||
// data found ..2
|
||||
[
|
||||
'message'=>'Get Data Successfully!',
|
||||
'alert-type'=>'success'
|
||||
],
|
||||
// data updated ..3
|
||||
[
|
||||
'message'=>'Data Updated Successfully!',
|
||||
'alert-type'=>'success'
|
||||
],
|
||||
// validator ..4
|
||||
[
|
||||
'message'=>'Sorry!!Data validation Failed!',
|
||||
'alert-type'=>'error'
|
||||
],
|
||||
// bad request ..5
|
||||
[
|
||||
'message'=>'Sorry!! You\'ar Send Bad Request!',
|
||||
'alert-type'=>'error'
|
||||
],
|
||||
// data not found ..6
|
||||
[
|
||||
'message'=>'Sorry!! Data Not Found!',
|
||||
'alert-type'=>'error'
|
||||
],
|
||||
// data already exist ..7
|
||||
[
|
||||
'message'=>'Sorry!! Data Already Exists!',
|
||||
'alert-type'=>'error'
|
||||
],
|
||||
// unauthorized request ..8
|
||||
[
|
||||
'message'=>'Sorry!! Unauthenticated Request!',
|
||||
'alert-type'=>'error'
|
||||
],
|
||||
// time request error ..9
|
||||
[
|
||||
'message'=>'Sorry!! Try After Few Time!',
|
||||
'alert-type'=>'error'
|
||||
],
|
||||
// check balance error ..10
|
||||
[
|
||||
'message'=>'Sorry!! Unavailable Balance!',
|
||||
'alert-type'=>'error'
|
||||
],
|
||||
// requested accepted ..11
|
||||
[
|
||||
'message'=>'Data Request Accepted!',
|
||||
'alert-type'=>'success'
|
||||
],
|
||||
// requested rejected ..12
|
||||
[
|
||||
'message'=>'Data Request Rejected!',
|
||||
'alert-type'=>'success'
|
||||
],
|
||||
// requested not modify ..13
|
||||
[
|
||||
'message'=>'Data Not Modified!',
|
||||
'alert-type'=>'warning'
|
||||
],
|
||||
// requested deleted ..14
|
||||
[
|
||||
'message'=>'Data deleted!',
|
||||
'alert-type'=>'success'
|
||||
],
|
||||
// requested deleted ..15
|
||||
[
|
||||
'message'=>'Bad Request!',
|
||||
'alert-type'=>'success'
|
||||
]
|
||||
];
|
||||
|
||||
protected function setSuccess($message)
|
||||
{
|
||||
session()->flash('type', 'success');
|
||||
session()->flash('message', $message);
|
||||
}
|
||||
|
||||
protected function setError($message)
|
||||
{
|
||||
session()->flash('type', 'warning');
|
||||
session()->flash('message', $message);
|
||||
}
|
||||
|
||||
protected function setDelete($message)
|
||||
{
|
||||
session()->flash('type', 'warning');
|
||||
session()->flash('message', $message);
|
||||
}
|
||||
|
||||
protected function respondWithValidatorError($message = '', $data = [], $code = 422)
|
||||
{
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
],$code);
|
||||
}
|
||||
|
||||
protected function respondWithSuccess($message = '', $data = [], $code = 200)
|
||||
{
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
],$code);
|
||||
}
|
||||
|
||||
protected function respondWithCreated($message = '', $data = [], $code = 201)
|
||||
{
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
],$code);
|
||||
}
|
||||
|
||||
protected function respondWithFound($message = '', $data = [], $code = 302)
|
||||
{
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
],$code);
|
||||
}
|
||||
|
||||
protected function respondWithUpdate($message = '', $data = [], $code = 426)
|
||||
{
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
],$code);
|
||||
}
|
||||
protected function respondWithAccept($message = '', $data = [], $code = 202)
|
||||
{
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
],$code);
|
||||
}
|
||||
protected function respondWithReject($message = '', $data = [], $code = 406)
|
||||
{
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
],$code);
|
||||
}
|
||||
protected function respondWithNotModify($message = '', $data = [], $code = 304)
|
||||
{
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
],$code);
|
||||
}
|
||||
|
||||
protected function respondWithError($message = '', $data = [], $code = 400)
|
||||
{
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
],$code);
|
||||
}
|
||||
|
||||
protected function respondWithErrorNotFound($message = '', $data = [], $code = 404)
|
||||
{
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
],$code);
|
||||
}
|
||||
|
||||
protected function respondWithAlreadyExists($message = '', $data = [], $code = 208)
|
||||
{
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
],$code);
|
||||
}
|
||||
|
||||
protected function respondWithUnauthorized($message = '', $data = [], $code = 401)
|
||||
{
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
],$code);
|
||||
}
|
||||
protected function respondWithNotAcceptable($message = '', $data = [], $code = 406)
|
||||
{
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
],$code);
|
||||
}
|
||||
protected function respondWithUnavilableBalance($message = '', $data = [], $code = 451)
|
||||
{
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
],$code);
|
||||
}
|
||||
protected function respondWithDelete($message = '', $data = [], $code = 204)
|
||||
{
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
],$code);
|
||||
}
|
||||
protected function respondWithBadRequest($message = '', $data = [], $code = 400)
|
||||
{
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
],$code);
|
||||
}
|
||||
protected function respondWithNotExtanded($message = '', $data = [], $code = 510)
|
||||
{
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
],$code);
|
||||
}
|
||||
}
|
||||
17
app/Http/Controllers/DataDeletionController.php
Normal file
17
app/Http/Controllers/DataDeletionController.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Option;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class DataDeletionController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$page_data = get_option('manage-pages');
|
||||
$general = Option::where('key','general')->first();
|
||||
|
||||
return view('web.data-deletion.index', compact('page_data', 'general'));
|
||||
}
|
||||
}
|
||||
291
app/Http/Controllers/PaymentController.php
Normal file
291
app/Http/Controllers/PaymentController.php
Normal file
@@ -0,0 +1,291 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Plan;
|
||||
use App\Models\User;
|
||||
use App\Models\Gateway;
|
||||
use App\Models\Business;
|
||||
use App\Helpers\HasUploader;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\PlanSubscribe;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Modules\AffiliateAddon\App\Models\Affiliate;
|
||||
use Modules\AffiliateAddon\App\Models\AffiliateTransaction;
|
||||
|
||||
class PaymentController extends Controller
|
||||
{
|
||||
use HasUploader;
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index($plan_id, $business_id)
|
||||
{
|
||||
$plan = Plan::findOrFail($plan_id);
|
||||
session()->put('business_id', $business_id);
|
||||
session()->put('platform', request('platform') ?? 'web');
|
||||
$business = Business::findOrFail($business_id);
|
||||
$plan_data = plan_data($business_id);
|
||||
|
||||
$has_free_subscriptions = Plan::where('subscriptionPrice', '<=', 0)->orWhere('offerPrice', '<=', 0)->first();
|
||||
|
||||
if ($plan->subscriptionPrice <= 0 && $has_free_subscriptions) {
|
||||
return redirect(route('order.status', ['status' => 'failed']))->with('message', __('Sorry, you cannot subscribe to a free plan again.'));
|
||||
}
|
||||
|
||||
if (
|
||||
session('platform') == 'web' && ($plan_data ?? false) && ($plan_data->plan_id == $plan->id && $business->will_expire > now()->addDays(7)) ||
|
||||
($business->will_expire >= now()->addDays($plan->duration))
|
||||
) {
|
||||
return redirect(route('order.status', ['status' => 'failed']))->with('message', __('You have already subscribed to this plan. Please try again after - ' . formatted_date($business->will_expire)));
|
||||
}
|
||||
|
||||
$gateways = Gateway::with('currency:id,code,rate,symbol,position')->where('status', 1)->get();
|
||||
|
||||
return view('payments.index', compact('gateways', 'plan'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function payment(Request $request, $plan_id, $gateway_id)
|
||||
{
|
||||
$request->validate([
|
||||
'phone' => 'max:15|min:5',
|
||||
]);
|
||||
|
||||
$plan = Plan::findOrFail($plan_id);
|
||||
$gateway = Gateway::findOrFail($gateway_id);
|
||||
$business = Business::findOrFail(session("business_id"));
|
||||
|
||||
if ($gateway->is_manual) {
|
||||
$request->validate([
|
||||
'attachment' => 'required|mimes:jpg,jpeg,png,pdf|file',
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$attachment = $request->attachment ? $this->upload($request, 'attachment') : NULL;
|
||||
|
||||
$subscribe = PlanSubscribe::create([
|
||||
'plan_id' => $plan->id,
|
||||
'duration' => $plan->duration,
|
||||
'business_id' => $business->id,
|
||||
'price' => $plan->subscriptionPrice,
|
||||
'gateway_id' => $gateway_id,
|
||||
'payment_status' => 'unpaid',
|
||||
'allow_multibranch' => $plan->allow_multibranch,
|
||||
'addon_domain_limit' => $plan->addon_domain_limit ?? 0,
|
||||
'subdomain_limit' => $plan->subdomain_limit ?? 0,
|
||||
'notes' => [
|
||||
'manual_data' => $request->manual_data,
|
||||
'attachment' => $attachment
|
||||
],
|
||||
]);
|
||||
|
||||
sendNotification($subscribe->id, route('admin.subscription-reports.index', ['id' => $subscribe->id]), __('New subscription purchased requested.'));
|
||||
|
||||
DB::commit();
|
||||
return redirect(route('order.status', ['status' => 'success']))->with('message', __('New subscription purchased requested.'));
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return redirect(route('order.status', ['status' => 'failed']))->with('message', __('Something went wrong!'));
|
||||
}
|
||||
}
|
||||
|
||||
$amount = $plan->offerPrice ?? $plan->subscriptionPrice;
|
||||
|
||||
if ($gateway->namespace == 'App\Library\SslCommerz') {
|
||||
Session::put('fund_callback.success_url', '/ssl-commerz//payment/success');
|
||||
Session::put('fund_callback.cancel_url', '/ssl-commerz//payment/failed');
|
||||
} else {
|
||||
Session::put('fund_callback.success_url', '/payment/success');
|
||||
Session::put('fund_callback.cancel_url', '/payment/failed');
|
||||
}
|
||||
|
||||
$currency = $gateway->currency;
|
||||
$user = User::where('business_id', $business->id)->first();
|
||||
|
||||
$payment_data['country'] = $request->country ?? 'ZMW';
|
||||
$payment_data['currency'] = $currency->code ?? 'USD';
|
||||
$payment_data['email'] = $user->email;
|
||||
$payment_data['name'] = $business->companyName;
|
||||
$payment_data['phone'] = $request->phone ?? $business->phoneNumber;
|
||||
$payment_data['billName'] = __('Make plan purchase payment');
|
||||
$payment_data['amount'] = $amount;
|
||||
$payment_data['mode'] = $gateway->mode;
|
||||
$payment_data['charge'] = $gateway->charge ?? 0;
|
||||
$payment_data['pay_amount'] = round(convert_money($amount, $currency) + $gateway->charge);
|
||||
$payment_data['gateway_id'] = $gateway->id;
|
||||
$payment_data['payment_type'] = 'plan_payment';
|
||||
$payment_data['request_from'] = 'merchant';
|
||||
$payment_data['plan_id'] = $plan_id;
|
||||
$payment_data['business_id'] = $business->id;
|
||||
$payment_data['platform'] = session('platform');
|
||||
|
||||
foreach ($gateway->data ?? [] as $key => $info) {
|
||||
$payment_data[$key] = $info;
|
||||
}
|
||||
|
||||
session()->put('gateway_id', $gateway->id);
|
||||
session()->put('plan', $plan);
|
||||
|
||||
$redirect = $gateway->namespace::make_payment($payment_data);
|
||||
return $redirect;
|
||||
}
|
||||
|
||||
public function success()
|
||||
{
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
|
||||
$plan = session('plan');
|
||||
$gateway_id = session('gateway_id');
|
||||
|
||||
if (!$plan && !session('plan_id')) {
|
||||
return redirect(route('order.status', ['status' => 'failed']))->with('error', __('Transaction failed, Please try again.'));
|
||||
}
|
||||
|
||||
if (session('plan_id') && !$plan) {
|
||||
$plan = Plan::findOrFail(session('plan_id'));
|
||||
}
|
||||
|
||||
$business = Business::findOrFail(session("business_id"));
|
||||
|
||||
$subscribe = PlanSubscribe::create([
|
||||
'plan_id' => $plan->id,
|
||||
'payment_status' => 'paid',
|
||||
'gateway_id' => $gateway_id,
|
||||
'duration' => $plan->duration,
|
||||
'business_id' => $business->id,
|
||||
'price' => $plan->subscriptionPrice,
|
||||
'allow_multibranch' => $plan->allow_multibranch,
|
||||
'addon_domain_limit' => $plan->addon_domain_limit ?? 0,
|
||||
'subdomain_limit' => $plan->subdomain_limit ?? 0,
|
||||
]);
|
||||
|
||||
$business->update([
|
||||
'subscriptionDate' => now(),
|
||||
'plan_subscribe_id' => $subscribe->id,
|
||||
'will_expire' => now()->addDays($plan->duration),
|
||||
]);
|
||||
|
||||
if (moduleCheck('AffiliateAddon') && $business->affiliator_id) {
|
||||
$affiliateUser = User::find($business->affiliator_id);
|
||||
|
||||
if ($affiliateUser && $plan->affiliate_commission > 0) {
|
||||
$commission = ($plan->subscriptionPrice * $plan->affiliate_commission) / 100;
|
||||
|
||||
Affiliate::where('user_id', $affiliateUser->id)->increment('balance', $commission);
|
||||
|
||||
AffiliateTransaction::create([
|
||||
'user_id' => $affiliateUser->id,
|
||||
'business_id' => $business->id,
|
||||
'trx' => strtoupper(str()->random(10)),
|
||||
'type' => 'credit',
|
||||
'amount' => $commission,
|
||||
'title' => 'Commission from Order #' . $subscribe->id,
|
||||
'reference_id' => $subscribe->id,
|
||||
'reference_type' => 'PlanSubscribe',
|
||||
'note' => 'User purchased via your referral link',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
session()->forget('plan');
|
||||
session()->forget('plan_id');
|
||||
session()->forget('gateway_id');
|
||||
session()->forget('business_id');
|
||||
Cache::forget('plan-data-' . $business->id);
|
||||
|
||||
DB::commit();
|
||||
return redirect(route('order.status', ['status' => 'success']))->with('message', __('New subscription order successfully.'));
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return redirect(route('order.status', ['status' => 'failed']))->with('message', __('Something went wrong!'));
|
||||
}
|
||||
}
|
||||
|
||||
public function failed()
|
||||
{
|
||||
if (session('platform') == 'web') {
|
||||
$payment_msg = session('payment_msg');
|
||||
session()->forget('payment_msg');
|
||||
return redirect(route('business.subscriptions.index'))->with('error', $payment_msg ?? __('Transaction failed, Please try again.'));
|
||||
}
|
||||
|
||||
return redirect(route('order.status', ['status' => 'failed']))->with('message', __('Something went wrong!'));
|
||||
}
|
||||
|
||||
public function sslCommerzSuccess(Request $request)
|
||||
{
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
|
||||
if (!$request->value_a || !$request->value_b || !$request->value_c) {
|
||||
return redirect(route('order.status', ['status' => 'failed']))->with('error', __('Transaction failed, Please try again.'));
|
||||
}
|
||||
|
||||
$plan = session('plan');
|
||||
$gateway_id = session('gateway_id');
|
||||
if (!$plan) {
|
||||
return redirect(route('order.status', ['status' => 'failed']))->with('error', __('Transaction failed, Please try again.'));
|
||||
}
|
||||
|
||||
$business = Business::findOrFail(session("business_id"));
|
||||
|
||||
$subscribe = PlanSubscribe::create([
|
||||
'plan_id' => $plan->id,
|
||||
'payment_status' => 'paid',
|
||||
'gateway_id' => $gateway_id,
|
||||
'duration' => $plan->duration,
|
||||
'business_id' => $business->id,
|
||||
'price' => $plan->subscriptionPrice,
|
||||
'allow_multibranch' => $plan->allow_multibranch,
|
||||
'addon_domain_limit' => $plan->addon_domain_limit ?? 0,
|
||||
'subdomain_limit' => $plan->subdomain_limit ?? 0,
|
||||
]);
|
||||
|
||||
$business->update([
|
||||
'subscriptionDate' => now(),
|
||||
'plan_subscribe_id' => $subscribe->id,
|
||||
'will_expire' => now()->addDays($plan->duration),
|
||||
]);
|
||||
|
||||
session()->forget('gateway_id');
|
||||
session()->forget('plan');
|
||||
Cache::forget('plan-data-' . $business->id);
|
||||
|
||||
DB::commit();
|
||||
return redirect(route('order.status', ['status' => 'success']))->with('message', __('New subscription order successfully.'));
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return redirect(route('order.status', ['status' => 'failed']))->with('message', __('Something went wrong!'));
|
||||
}
|
||||
}
|
||||
|
||||
public function sslCommerzFailed()
|
||||
{
|
||||
return redirect(route('order.status', ['status' => 'failed']))->with('error', __('Transaction failed, Please try again.'));
|
||||
}
|
||||
|
||||
public function orderStatus()
|
||||
{
|
||||
if (session('platform') == 'web') {
|
||||
if (moduleCheck('Business')) {
|
||||
if (session('user_id')) {
|
||||
session()->forget('user_id');
|
||||
return redirect(route('business.dashboard.index'))->with('message', request('message') ?? __('Subscription order completed.'));
|
||||
} else {
|
||||
return redirect(route('business.subscriptions.index'))->with('message', request('message') ?? __('New subscription order successfully.'));
|
||||
}
|
||||
} else {
|
||||
return redirect(route('home', ['success_modal' => 1]))->with('message', request('message') ?? __('Subscription order successfully, Please download the apk for manage your business.'));
|
||||
}
|
||||
}
|
||||
session()->forget('platform');
|
||||
return request('status');
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user