migrate to gtea from bistbucket

This commit is contained in:
2026-03-15 17:08:23 +07:00
commit 129ca2260c
3716 changed files with 566316 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
[docker-compose.yml]
indent_size = 4

View File

@@ -0,0 +1,70 @@
APP_NAME="Mighty Restaurant"
APP_ENV=local
APP_KEY=base64:pTtyyGt6XClh4fiSLpaiD33fl+trueJg8xbJ5O9xusc=
APP_DEBUG=false
APP_URL=http://127.0.0.1:8000
APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US
APP_MAINTENANCE_DRIVER=file
# APP_MAINTENANCE_STORE=database
PHP_CLI_SERVER_WORKERS=4
BCRYPT_ROUNDS=12
LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=codenichebd_restaurant
DB_USERNAME=root
DB_PASSWORD=
SESSION_DRIVER=file
SESSION_LIFETIME=120
SESSION_ENCRYPT=true
SESSION_PATH=/
SESSION_DOMAIN=null
BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
QUEUE_CONNECTION=file
CACHE_STORE=file
# CACHE_PREFIX=
MEMCACHED_HOST=127.0.0.1
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_HOST=sandbox.smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=2ec3b6026804f8
MAIL_PASSWORD=0e6a7e10c57da7
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
VITE_APP_NAME="${APP_NAME}"
ORDER_CANCEL_LIMIT=5
USER_FCM_TOKEN=""
VERCEL_TOKEN=""
VERCEL_PROJECT_ID=""
DEVICE_API_KEY=""

11
public/restaurant/.gitattributes vendored Normal file
View File

@@ -0,0 +1,11 @@
* text=auto eol=lf
*.blade.php diff=html
*.css diff=css
*.html diff=html
*.md diff=markdown
*.php diff=php
/.github export-ignore
CHANGELOG.md export-ignore
.styleci.yml export-ignore

24
public/restaurant/.gitignore vendored Normal file
View File

@@ -0,0 +1,24 @@
*.log
.DS_Store
.env
.env.backup
.env.production
.phpactor.json
.phpunit.result.cache
/.fleet
/.idea
/.nova
/.phpunit.cache
/.vscode
/.zed
/auth.json
/node_modules
/public/build
/public/hot
/public/storage
/storage/*.key
/storage/pail
/vendor
Homestead.json
Homestead.yaml
Thumbs.db

View File

@@ -0,0 +1,67 @@
<IfModule mod_rewrite.c>
RewriteEngine On
# Redirect to public folder
RewriteRule ^(.*)$ /restaurant/$1 [L]
</IfModule>
# Laravel specific rules
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
<IfModule mod_headers.c>
<FilesMatch "\.(png|jpg|jpeg|gif|css|js|ico|svg|woff|woff2)$">
Header set Cache-Control "max-age=31536000, public"
</FilesMatch>
</IfModule>
# Handle front controller
<IfModule mod_rewrite.c>
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L]
</IfModule>
<IfModule mod_headers.c>
<FilesMatch "\.(jpg|jpeg|png|webp|pdf|webm|ogg)$">
Header set Access-Control-Allow-Origin "*"
</FilesMatch>
</IfModule>
# BEGIN cPanel-generated php ini directives, do not edit
# Manual editing of this file may result in unexpected behavior.
# To make changes to this file, use the cPanel MultiPHP INI Editor (Home >> Software >> MultiPHP INI Editor)
# For more information, read our documentation (https://go.cpanel.net/EA4ModifyINI)
<IfModule php7_module>
php_flag display_errors Off
php_value max_execution_time 30000
php_value max_input_time 300
php_value max_input_vars 10000
php_value memory_limit 1024M
php_value post_max_size 1024M
php_value session.gc_maxlifetime 1440
php_value session.save_path "/var/cpanel/php/sessions/ea-php74"
php_value upload_max_filesize 1024M
php_flag zlib.output_compression On
</IfModule>
<IfModule lsapi_module>
php_flag display_errors Off
php_value max_execution_time 30000
php_value max_input_time 300
php_value max_input_vars 10000
php_value memory_limit 1024M
php_value post_max_size 1024M
php_value session.gc_maxlifetime 1440
php_value session.save_path "/var/cpanel/php/sessions/ea-php74"
php_value upload_max_filesize 1024M
php_flag zlib.output_compression On
</IfModule>
# END cPanel-generated php ini directives, do not edit
# php -- BEGIN cPanel-generated handler, do not edit
# Set the “ea-php72” package as the default “PHP” programming language.
#<IfModule mime_module>
# AddHandler application/x-httpd-ea-php83___lsphp .php .php8 .phtml
#</IfModule>
# php -- END cPanel-generated handler, do not edit

View File

@@ -0,0 +1,61 @@
<IfModule mod_rewrite.c>
RewriteEngine On
# Redirect to public folder
RewriteRule ^(.*)$ public/$1 [L]
</IfModule>
# Laravel specific rules
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
<IfModule mod_headers.c>
<FilesMatch "\.(png|jpg|jpeg|gif|css|js|ico|svg|woff|woff2)$">
Header set Cache-Control "max-age=31536000, public"
</FilesMatch>
</IfModule>
# Handle front controller
<IfModule mod_rewrite.c>
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L]
</IfModule>
# BEGIN cPanel-generated php ini directives, do not edit
# Manual editing of this file may result in unexpected behavior.
# To make changes to this file, use the cPanel MultiPHP INI Editor (Home >> Software >> MultiPHP INI Editor)
# For more information, read our documentation (https://go.cpanel.net/EA4ModifyINI)
<IfModule php7_module>
php_flag display_errors Off
php_value max_execution_time 30000
php_value max_input_time 300
php_value max_input_vars 10000
php_value memory_limit 1024M
php_value post_max_size 1024M
php_value session.gc_maxlifetime 1440
php_value session.save_path "/var/cpanel/php/sessions/ea-php74"
php_value upload_max_filesize 1024M
php_flag zlib.output_compression On
</IfModule>
<IfModule lsapi_module>
php_flag display_errors Off
php_value max_execution_time 30000
php_value max_input_time 300
php_value max_input_vars 10000
php_value memory_limit 1024M
php_value post_max_size 1024M
php_value session.gc_maxlifetime 1440
php_value session.save_path "/var/cpanel/php/sessions/ea-php74"
php_value upload_max_filesize 1024M
php_flag zlib.output_compression On
</IfModule>
# END cPanel-generated php ini directives, do not edit
# php -- BEGIN cPanel-generated handler, do not edit
# Set the “ea-php83” package as the default “PHP” programming language.
<IfModule mime_module>
AddHandler application/x-httpd-ea-php83 .php .php8 .phtml
</IfModule>
# php -- END cPanel-generated handler, do not edit

View File

@@ -0,0 +1,168 @@
<?php
namespace Modules\Accounting\Repositories;
use App\Abstracts\EntityRepository;
use Exception;
use Illuminate\Contracts\Pagination\Paginator;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Query\Builder;
use Modules\Accounting\Models\Account;
use Symfony\Component\HttpFoundation\Response;
class AccountRepository extends EntityRepository
{
public string $table = Account::TABLE_NAME;
protected array $fillableColumns = [
'restaurant_id',
'name',
'code',
'type',
'opening_balance',
'current_balance',
'status',
];
protected function getQuery(): Builder
{
return parent::getQuery();
}
protected function getFilterData(array $filterData = []): array
{
$defaultArgs = [
'perPage' => 10,
'search' => '',
'orderBy' => 'id',
'order' => 'desc',
'with_deleted' => false,
];
return array_merge($defaultArgs, $filterData);
}
private function getAccountQuery(): Builder
{
return $this->getQuery()
->select(
"{$this->table}.id",
"{$this->table}.restaurant_id",
"{$this->table}.name",
"{$this->table}.code",
"{$this->table}.type",
"{$this->table}.opening_balance",
"{$this->table}.current_balance",
"{$this->table}.status",
"{$this->table}.created_at",
"{$this->table}.updated_at",
"{$this->table}.deleted_at"
);
}
protected function filterSearchQuery(Builder|EloquentBuilder $query, string $searchedText): Builder
{
$searchable = "%$searchedText%";
return $query->where("{$this->table}.name", 'LIKE', $searchable)
->orWhere("{$this->table}.status", 'LIKE', $searchable);
}
public function getAll(array $filterData = []): Paginator
{
$filter = $this->getFilterData($filterData);
$query = $this->getAccountQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
if (! empty($filter['search'])) {
$query = $this->filterSearchQuery($query, $filter['search']);
}
return $query
->orderBy($filter['orderBy'], $filter['order'])
->paginate($filter['perPage']);
}
public function getCount(array $filterData = []): int
{
$filter = $this->getFilterData($filterData);
$query = $this->getQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
return $query->count();
}
/**
* @throws Exception
*/
public function getByColumn(string $columnName, $columnValue, array $selects = ['*']): ?object
{
$item = $this->getAccountQuery()
->where($columnName, $columnValue)
->first($selects);
if (empty($item)) {
throw new Exception(
$this->getExceptionMessage(static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE),
Response::HTTP_NOT_FOUND
);
}
return $item;
}
/**
* @throws Exception
*/
public function create(array $data): object
{
$data = $this->prepareForDB($data);
$id = $this->getQuery()->insertGetId($data);
return Account::find($id);
}
/**
* @throws Exception
*/
public function update(int $id, array $data): object
{
$item = Account::findOrFail($id);
$data = $this->prepareForDB($data, $item);
parent::update($id, $data);
return $this->getById($id);
}
/**
* @throws Exception
*/
public function prepareForDB(array $data, ?object $item = null): array
{
$data = parent::prepareForDB($data, $item);
if (empty($item)) {
$data['created_at'] = now();
$data['restaurant_id'] = $this->getCurrentRestaurantId();
$data['status'] = 1;
} else {
$data['updated_at'] = now();
}
return $data;
}
protected function getExceptionMessages(): array
{
return [
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'Account does not exist.',
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'Account could not be deleted.',
];
}
}

View File

@@ -0,0 +1,163 @@
<?php
namespace Modules\Accounting\Repositories;
use App\Abstracts\EntityRepository;
use Exception;
use Illuminate\Contracts\Pagination\Paginator;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Query\Builder;
use Modules\Accounting\Models\DepositCategory;
use Symfony\Component\HttpFoundation\Response;
class DepositCategoryRepository extends EntityRepository
{
public string $table = DepositCategory::TABLE_NAME;
protected array $fillableColumns = [
'restaurant_id',
'name',
'status',
'created_by',
'created_at',
'updated_at',
'deleted_at',
];
protected function getQuery(): Builder
{
return parent::getQuery();
}
protected function getFilterData(array $filterData = []): array
{
$defaultArgs = [
'perPage' => 10,
'search' => '',
'orderBy' => 'id',
'order' => 'desc',
'with_deleted' => false,
];
return array_merge($defaultArgs, $filterData);
}
private function getDepositCategoryQuery(): Builder
{
return $this->getQuery()
->select(
"{$this->table}.id",
"{$this->table}.restaurant_id",
"{$this->table}.name",
"{$this->table}.status",
"{$this->table}.created_at",
"{$this->table}.deleted_at"
);
}
protected function filterSearchQuery(Builder|EloquentBuilder $query, string $searchedText): Builder
{
$searchable = "%$searchedText%";
return $query->where("{$this->table}.name", 'LIKE', $searchable)
->orWhere("{$this->table}.status", 'LIKE', $searchable);
}
public function getAll(array $filterData = []): Paginator
{
$filter = $this->getFilterData($filterData);
$query = $this->getDepositCategoryQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
if (! empty($filter['search'])) {
$query = $this->filterSearchQuery($query, $filter['search']);
}
return $query
->orderBy($filter['orderBy'], $filter['order'])
->paginate($filter['perPage']);
}
public function getCount(array $filterData = []): int
{
$filter = $this->getFilterData($filterData);
$query = $this->getQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
return $query->count();
}
/**
* @throws Exception
*/
public function getByColumn(string $columnName, $columnValue, array $selects = ['*']): ?object
{
$item = $this->getDepositCategoryQuery()
->where($columnName, $columnValue)
->first($selects);
if (empty($item)) {
throw new Exception(
$this->getExceptionMessage(static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE),
Response::HTTP_NOT_FOUND
);
}
return $item;
}
/**
* @throws Exception
*/
public function create(array $data): object
{
$data = $this->prepareForDB($data);
$id = $this->getQuery()->insertGetId($data);
return DepositCategory::find($id);
}
/**
* @throws Exception
*/
public function update(int $id, array $data): object
{
$item = DepositCategory::findOrFail($id);
$data = $this->prepareForDB($data, $item);
parent::update($id, $data);
return $this->getById($id);
}
/**
* @throws Exception
*/
public function prepareForDB(array $data, ?object $item = null): array
{
$data = parent::prepareForDB($data, $item);
if (empty($item)) {
$data['created_at'] = now();
$data['restaurant_id'] = $this->getCurrentRestaurantId();
$data['status'] = 1;
} else {
$data['updated_at'] = now();
}
return $data;
}
protected function getExceptionMessages(): array
{
return [
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'DepositCategory does not exist.',
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'DepositCategory could not be deleted.',
];
}
}

View File

@@ -0,0 +1,179 @@
<?php
namespace Modules\Accounting\Repositories;
use App\Abstracts\EntityRepository;
use Exception;
use Illuminate\Contracts\Pagination\Paginator;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Query\Builder;
use Modules\Accounting\Models\Deposit;
use Symfony\Component\HttpFoundation\Response;
class DepositRepository extends EntityRepository
{
public string $table = Deposit::TABLE_NAME;
protected array $fillableColumns = [
'restaurant_id',
'fund_id',
'account_id',
'deposit_category_id',
'amount',
'transaction_date',
'voucher_no',
'received_from',
'note',
'created_by',
'status',
];
protected function getQuery(): Builder
{
return parent::getQuery();
}
protected function getFilterData(array $filterData = []): array
{
$defaultArgs = [
'perPage' => 10,
'search' => '',
'orderBy' => 'id',
'order' => 'desc',
'with_deleted' => false,
];
return array_merge($defaultArgs, $filterData);
}
private function getDepositQuery(): Builder
{
return $this->getQuery()
->select(
"{$this->table}.id",
"{$this->table}.restaurant_id",
"{$this->table}.fund_id",
"{$this->table}.account_id",
'accounts.name as account_name',
"{$this->table}.deposit_category_id",
'deposit_categories.name as category_name',
"{$this->table}.amount",
"{$this->table}.transaction_date",
"{$this->table}.voucher_no",
"{$this->table}.received_from",
"{$this->table}.note",
"{$this->table}.created_by",
"{$this->table}.status",
"{$this->table}.created_at",
"{$this->table}.deleted_at"
)
->leftJoin('deposit_categories', 'deposit_categories.id', '=', "{$this->table}.deposit_category_id")
->leftJoin('accounts', 'accounts.id', '=', "{$this->table}.account_id");
}
protected function filterSearchQuery(Builder|EloquentBuilder $query, string $searchedText): Builder
{
$searchable = "%$searchedText%";
return $query->where("{$this->table}.transaction_date", 'LIKE', $searchable)
->orWhere("{$this->table}.status", 'LIKE', $searchable);
}
public function getAll(array $filterData = []): Paginator
{
$filter = $this->getFilterData($filterData);
$query = $this->getDepositQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
if (! empty($filter['search'])) {
$query = $this->filterSearchQuery($query, $filter['search']);
}
return $query
->orderBy($filter['orderBy'], $filter['order'])
->paginate($filter['perPage']);
}
public function getCount(array $filterData = []): int
{
$filter = $this->getFilterData($filterData);
$query = $this->getQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
return $query->count();
}
/**
* @throws Exception
*/
public function getByColumn(string $columnName, $columnValue, array $selects = ['*']): ?object
{
$item = $this->getDepositQuery()
->where($columnName, $columnValue)
->first($selects);
if (empty($item)) {
throw new Exception(
$this->getExceptionMessage(static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE),
Response::HTTP_NOT_FOUND
);
}
return $item;
}
/**
* @throws Exception
*/
public function create(array $data): object
{
$data = $this->prepareForDB($data);
$id = $this->getQuery()->insertGetId($data);
return Deposit::find($id);
}
/**
* @throws Exception
*/
public function update(int $id, array $data): object
{
$item = Deposit::findOrFail($id);
$data = $this->prepareForDB($data, $item);
parent::update($id, $data);
return $this->getById($id);
}
/**
* @throws Exception
*/
public function prepareForDB(array $data, ?object $item = null): array
{
$data = parent::prepareForDB($data, $item);
if (empty($item)) {
$data['created_at'] = now();
$data['restaurant_id'] = $this->getCurrentRestaurantId();
$data['status'] = 1;
} else {
$data['updated_at'] = now();
}
return $data;
}
protected function getExceptionMessages(): array
{
return [
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'Deposit does not exist.',
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'Deposit could not be deleted.',
];
}
}

View File

@@ -0,0 +1,163 @@
<?php
namespace Modules\Accounting\Repositories;
use App\Abstracts\EntityRepository;
use Exception;
use Illuminate\Contracts\Pagination\Paginator;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Query\Builder;
use Modules\Accounting\Models\ExpenseCategory;
use Symfony\Component\HttpFoundation\Response;
class ExpenseCategoryRepository extends EntityRepository
{
public string $table = ExpenseCategory::TABLE_NAME;
protected array $fillableColumns = [
'restaurant_id',
'name',
'status',
'created_by',
'created_at',
'updated_at',
'deleted_at',
];
protected function getQuery(): Builder
{
return parent::getQuery();
}
protected function getFilterData(array $filterData = []): array
{
$defaultArgs = [
'perPage' => 10,
'search' => '',
'orderBy' => 'id',
'order' => 'desc',
'with_deleted' => false,
];
return array_merge($defaultArgs, $filterData);
}
private function getExpenseCategoryQuery(): Builder
{
return $this->getQuery()
->select(
"{$this->table}.id",
"{$this->table}.restaurant_id",
"{$this->table}.name",
"{$this->table}.status",
"{$this->table}.created_at",
"{$this->table}.deleted_at"
);
}
protected function filterSearchQuery(Builder|EloquentBuilder $query, string $searchedText): Builder
{
$searchable = "%$searchedText%";
return $query->where("{$this->table}.name", 'LIKE', $searchable)
->orWhere("{$this->table}.status", 'LIKE', $searchable);
}
public function getAll(array $filterData = []): Paginator
{
$filter = $this->getFilterData($filterData);
$query = $this->getExpenseCategoryQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
if (! empty($filter['search'])) {
$query = $this->filterSearchQuery($query, $filter['search']);
}
return $query
->orderBy($filter['orderBy'], $filter['order'])
->paginate($filter['perPage']);
}
public function getCount(array $filterData = []): int
{
$filter = $this->getFilterData($filterData);
$query = $this->getQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
return $query->count();
}
/**
* @throws Exception
*/
public function getByColumn(string $columnName, $columnValue, array $selects = ['*']): ?object
{
$item = $this->getExpenseCategoryQuery()
->where($columnName, $columnValue)
->first($selects);
if (empty($item)) {
throw new Exception(
$this->getExceptionMessage(static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE),
Response::HTTP_NOT_FOUND
);
}
return $item;
}
/**
* @throws Exception
*/
public function create(array $data): object
{
$data = $this->prepareForDB($data);
$id = $this->getQuery()->insertGetId($data);
return ExpenseCategory::find($id);
}
/**
* @throws Exception
*/
public function update(int $id, array $data): object
{
$item = ExpenseCategory::findOrFail($id);
$data = $this->prepareForDB($data, $item);
parent::update($id, $data);
return $this->getById($id);
}
/**
* @throws Exception
*/
public function prepareForDB(array $data, ?object $item = null): array
{
$data = parent::prepareForDB($data, $item);
if (empty($item)) {
$data['created_at'] = now();
$data['restaurant_id'] = $this->getCurrentRestaurantId();
$data['status'] = 1;
} else {
$data['updated_at'] = now();
}
return $data;
}
protected function getExceptionMessages(): array
{
return [
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'ExpenseCategory does not exist.',
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'ExpenseCategory could not be deleted.',
];
}
}

View File

@@ -0,0 +1,175 @@
<?php
namespace Modules\Accounting\Repositories;
use App\Abstracts\EntityRepository;
use Exception;
use Illuminate\Contracts\Pagination\Paginator;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Query\Builder;
use Modules\Accounting\Models\Expense;
use Symfony\Component\HttpFoundation\Response;
class ExpenseRepository extends EntityRepository
{
public string $table = Expense::TABLE_NAME;
protected array $fillableColumns = [
'restaurant_id',
'fund_id',
'account_id',
'expense_category_id',
'amount',
'transaction_date',
'voucher_no',
'received_from',
'note',
'created_by',
'status',
];
protected function getQuery(): Builder
{
return parent::getQuery();
}
protected function getFilterData(array $filterData = []): array
{
$defaultArgs = [
'perPage' => 10,
'search' => '',
'orderBy' => 'id',
'order' => 'desc',
'with_deleted' => false,
];
return array_merge($defaultArgs, $filterData);
}
private function getExpenseQuery(): Builder
{
return $this->getQuery()
->select(
"{$this->table}.id",
"{$this->table}.restaurant_id",
"{$this->table}.fund_id",
"{$this->table}.account_id",
"{$this->table}.expense_category_id",
"{$this->table}.amount",
"{$this->table}.transaction_date",
"{$this->table}.voucher_no",
"{$this->table}.received_from",
"{$this->table}.note",
"{$this->table}.created_by",
"{$this->table}.status",
"{$this->table}.created_at",
"{$this->table}.deleted_at"
);
}
protected function filterSearchQuery(Builder|EloquentBuilder $query, string $searchedText): Builder
{
$searchable = "%$searchedText%";
return $query->where("{$this->table}.transaction_date", 'LIKE', $searchable)
->orWhere("{$this->table}.status", 'LIKE', $searchable);
}
public function getAll(array $filterData = []): Paginator
{
$filter = $this->getFilterData($filterData);
$query = $this->getExpenseQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
if (! empty($filter['search'])) {
$query = $this->filterSearchQuery($query, $filter['search']);
}
return $query
->orderBy($filter['orderBy'], $filter['order'])
->paginate($filter['perPage']);
}
public function getCount(array $filterData = []): int
{
$filter = $this->getFilterData($filterData);
$query = $this->getQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
return $query->count();
}
/**
* @throws Exception
*/
public function getByColumn(string $columnName, $columnValue, array $selects = ['*']): ?object
{
$item = $this->getExpenseQuery()
->where($columnName, $columnValue)
->first($selects);
if (empty($item)) {
throw new Exception(
$this->getExceptionMessage(static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE),
Response::HTTP_NOT_FOUND
);
}
return $item;
}
/**
* @throws Exception
*/
public function create(array $data): object
{
$data = $this->prepareForDB($data);
$id = $this->getQuery()->insertGetId($data);
return Expense::find($id);
}
/**
* @throws Exception
*/
public function update(int $id, array $data): object
{
$item = Expense::findOrFail($id);
$data = $this->prepareForDB($data, $item);
parent::update($id, $data);
return $this->getById($id);
}
/**
* @throws Exception
*/
public function prepareForDB(array $data, ?object $item = null): array
{
$data = parent::prepareForDB($data, $item);
if (empty($item)) {
$data['created_at'] = now();
$data['restaurant_id'] = $this->getCurrentRestaurantId();
$data['status'] = 1;
} else {
$data['updated_at'] = now();
}
return $data;
}
protected function getExceptionMessages(): array
{
return [
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'Expense does not exist.',
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'Expense could not be deleted.',
];
}
}

View File

@@ -0,0 +1,169 @@
<?php
namespace Modules\Accounting\Repositories;
use App\Abstracts\EntityRepository;
use Exception;
use Illuminate\Contracts\Pagination\Paginator;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Query\Builder;
use Modules\Accounting\Models\Fund;
use Symfony\Component\HttpFoundation\Response;
class FundRepository extends EntityRepository
{
public string $table = Fund::TABLE_NAME;
protected array $fillableColumns = [
'restaurant_id',
'name',
'type',
'code',
'opening_balance',
'current_balance',
'is_default',
'status',
];
protected function getQuery(): Builder
{
return parent::getQuery();
}
protected function getFilterData(array $filterData = []): array
{
$defaultArgs = [
'perPage' => 10,
'search' => '',
'orderBy' => 'id',
'order' => 'desc',
'with_deleted' => false,
];
return array_merge($defaultArgs, $filterData);
}
private function getFundQuery(): Builder
{
return $this->getQuery()
->select(
"{$this->table}.id",
"{$this->table}.restaurant_id",
"{$this->table}.name",
"{$this->table}.type",
"{$this->table}.code",
"{$this->table}.opening_balance",
"{$this->table}.current_balance",
"{$this->table}.is_default",
"{$this->table}.status",
"{$this->table}.created_at",
"{$this->table}.deleted_at"
);
}
protected function filterSearchQuery(Builder|EloquentBuilder $query, string $searchedText): Builder
{
$searchable = "%$searchedText%";
return $query->where("{$this->table}.name", 'LIKE', $searchable)
->orWhere("{$this->table}.status", 'LIKE', $searchable);
}
public function getAll(array $filterData = []): Paginator
{
$filter = $this->getFilterData($filterData);
$query = $this->getFundQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
if (! empty($filter['search'])) {
$query = $this->filterSearchQuery($query, $filter['search']);
}
return $query
->orderBy($filter['orderBy'], $filter['order'])
->paginate($filter['perPage']);
}
public function getCount(array $filterData = []): int
{
$filter = $this->getFilterData($filterData);
$query = $this->getQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
return $query->count();
}
/**
* @throws Exception
*/
public function getByColumn(string $columnName, $columnValue, array $selects = ['*']): ?object
{
$item = $this->getFundQuery()
->where($columnName, $columnValue)
->first($selects);
if (empty($item)) {
throw new Exception(
$this->getExceptionMessage(static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE),
Response::HTTP_NOT_FOUND
);
}
return $item;
}
/**
* @throws Exception
*/
public function create(array $data): object
{
$data = $this->prepareForDB($data);
$id = $this->getQuery()->insertGetId($data);
return Fund::find($id);
}
/**
* @throws Exception
*/
public function update(int $id, array $data): object
{
$item = Fund::findOrFail($id);
$data = $this->prepareForDB($data, $item);
parent::update($id, $data);
return $this->getById($id);
}
/**
* @throws Exception
*/
public function prepareForDB(array $data, ?object $item = null): array
{
$data = parent::prepareForDB($data, $item);
if (empty($item)) {
$data['created_at'] = now();
$data['restaurant_id'] = $this->getCurrentRestaurantId();
$data['status'] = 1;
} else {
$data['updated_at'] = now();
}
return $data;
}
protected function getExceptionMessages(): array
{
return [
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'Fund does not exist.',
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'Fund could not be deleted.',
];
}
}

View File

@@ -0,0 +1,163 @@
<?php
namespace Modules\Accounting\Repositories;
use App\Abstracts\EntityRepository;
use Exception;
use Illuminate\Contracts\Pagination\Paginator;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Query\Builder;
use Modules\Accounting\Models\FundTransfer;
use Symfony\Component\HttpFoundation\Response;
class FundTransferRepository extends EntityRepository
{
public string $table = FundTransfer::TABLE_NAME;
protected array $fillableColumns = [
'restaurant_id',
'name',
'status',
'created_by',
'created_at',
'updated_at',
'deleted_at',
];
protected function getQuery(): Builder
{
return parent::getQuery();
}
protected function getFilterData(array $filterData = []): array
{
$defaultArgs = [
'perPage' => 10,
'search' => '',
'orderBy' => 'id',
'order' => 'desc',
'with_deleted' => false,
];
return array_merge($defaultArgs, $filterData);
}
private function getFundTransferQuery(): Builder
{
return $this->getQuery()
->select(
"{$this->table}.id",
"{$this->table}.restaurant_id",
"{$this->table}.name",
"{$this->table}.status",
"{$this->table}.created_at",
"{$this->table}.deleted_at"
);
}
protected function filterSearchQuery(Builder|EloquentBuilder $query, string $searchedText): Builder
{
$searchable = "%$searchedText%";
return $query->where("{$this->table}.name", 'LIKE', $searchable)
->orWhere("{$this->table}.status", 'LIKE', $searchable);
}
public function getAll(array $filterData = []): Paginator
{
$filter = $this->getFilterData($filterData);
$query = $this->getFundTransferQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
if (! empty($filter['search'])) {
$query = $this->filterSearchQuery($query, $filter['search']);
}
return $query
->orderBy($filter['orderBy'], $filter['order'])
->paginate($filter['perPage']);
}
public function getCount(array $filterData = []): int
{
$filter = $this->getFilterData($filterData);
$query = $this->getQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
return $query->count();
}
/**
* @throws Exception
*/
public function getByColumn(string $columnName, $columnValue, array $selects = ['*']): ?object
{
$item = $this->getFundTransferQuery()
->where($columnName, $columnValue)
->first($selects);
if (empty($item)) {
throw new Exception(
$this->getExceptionMessage(static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE),
Response::HTTP_NOT_FOUND
);
}
return $item;
}
/**
* @throws Exception
*/
public function create(array $data): object
{
$data = $this->prepareForDB($data);
$id = $this->getQuery()->insertGetId($data);
return FundTransfer::find($id);
}
/**
* @throws Exception
*/
public function update(int $id, array $data): object
{
$item = FundTransfer::findOrFail($id);
$data = $this->prepareForDB($data, $item);
parent::update($id, $data);
return $this->getById($id);
}
/**
* @throws Exception
*/
public function prepareForDB(array $data, ?object $item = null): array
{
$data = parent::prepareForDB($data, $item);
if (empty($item)) {
$data['created_at'] = now();
$data['restaurant_id'] = $this->getCurrentRestaurantId();
$data['status'] = 1;
} else {
$data['updated_at'] = now();
}
return $data;
}
protected function getExceptionMessages(): array
{
return [
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'FundTransfer does not exist.',
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'FundTransfer could not be deleted.',
];
}
}

View File

@@ -0,0 +1,189 @@
<?php
namespace Modules\Accounting\Repositories;
use App\Abstracts\EntityRepository;
use Exception;
use Illuminate\Contracts\Pagination\Paginator;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\Auth;
use Modules\Accounting\Models\TipDistribution;
use Symfony\Component\HttpFoundation\Response;
class TipDistributionRepository extends EntityRepository
{
public string $table = TipDistribution::TABLE_NAME;
protected array $fillableColumns = [
'restaurant_id',
'waiter_id',
'account_id',
'amount',
'created_by',
'distributed_at',
'status',
'created_by',
'created_at',
'updated_at',
'deleted_at',
];
protected function getQuery(): Builder
{
return parent::getQuery();
}
protected function getFilterData(array $filterData = []): array
{
$defaultArgs = [
'perPage' => 10,
'search' => '',
'orderBy' => 'id',
'order' => 'desc',
'with_deleted' => false,
];
return array_merge($defaultArgs, $filterData);
}
private function getTipDistributionQuery(): Builder
{
return $this->getQuery()
->leftJoin('users as waiter_user', 'waiter_user.id', '=', "{$this->table}.waiter_id")
->leftJoin('accounts', 'accounts.id', '=', "{$this->table}.account_id")
->leftJoin('users as creator_user', 'creator_user.id', '=', "{$this->table}.created_by")
->select(
"{$this->table}.id",
"{$this->table}.restaurant_id",
// waiter
"{$this->table}.waiter_id",
'waiter_user.first_name as waiter_name',
// account
"{$this->table}.account_id",
'accounts.name as account_name',
// tip info
"{$this->table}.amount",
"{$this->table}.distributed_at",
// creator
"{$this->table}.created_by",
'creator_user.first_name as created_by_name',
// others
"{$this->table}.status",
"{$this->table}.created_at",
"{$this->table}.deleted_at"
);
}
protected function filterSearchQuery(Builder|EloquentBuilder $query, string $searchedText): Builder
{
$searchable = "%$searchedText%";
return $query->where("{$this->table}.name", 'LIKE', $searchable)
->orWhere("{$this->table}.status", 'LIKE', $searchable);
}
public function getAll(array $filterData = []): Paginator
{
$filter = $this->getFilterData($filterData);
$query = $this->getTipDistributionQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
if (! empty($filter['search'])) {
$query = $this->filterSearchQuery($query, $filter['search']);
}
return $query
->orderBy($filter['orderBy'], $filter['order'])
->paginate($filter['perPage']);
}
public function getCount(array $filterData = []): int
{
$filter = $this->getFilterData($filterData);
$query = $this->getQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
return $query->count();
}
/**
* @throws Exception
*/
public function getByColumn(string $columnName, $columnValue, array $selects = ['*']): ?object
{
$item = $this->getTipDistributionQuery()
->where($columnName, $columnValue)
->first($selects);
if (empty($item)) {
throw new Exception(
$this->getExceptionMessage(static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE),
Response::HTTP_NOT_FOUND
);
}
return $item;
}
/**
* @throws Exception
*/
public function create(array $data): object
{
$data = $this->prepareForDB($data);
$id = $this->getQuery()->insertGetId($data);
return TipDistribution::find($id);
}
/**
* @throws Exception
*/
public function update(int $id, array $data): object
{
$item = TipDistribution::findOrFail($id);
$data = $this->prepareForDB($data, $item);
parent::update($id, $data);
return $this->getById($id);
}
/**
* @throws Exception
*/
public function prepareForDB(array $data, ?object $item = null): array
{
$data = parent::prepareForDB($data, $item);
if (empty($item)) {
$data['created_at'] = now();
$data['created_by'] = Auth::id();
$data['restaurant_id'] = $this->getCurrentRestaurantId();
$data['status'] = 1;
} else {
$data['updated_at'] = now();
}
return $data;
}
protected function getExceptionMessages(): array
{
return [
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'TipDistribution does not exist.',
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'TipDistribution could not be deleted.',
];
}
}

View File

@@ -0,0 +1,176 @@
<?php
namespace Modules\Accounting\Repositories;
use App\Abstracts\EntityRepository;
use Exception;
use Illuminate\Contracts\Pagination\Paginator;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Query\Builder;
use Modules\Accounting\Models\Tip;
use Symfony\Component\HttpFoundation\Response;
class TipRepository extends EntityRepository
{
public string $table = Tip::TABLE_NAME;
protected array $fillableColumns = [
'restaurant_id',
'waiter_id',
'order_id',
'amount',
'collected_at',
'status',
'created_at',
'updated_at',
'deleted_at',
];
protected function getQuery(): Builder
{
return parent::getQuery();
}
protected function getFilterData(array $filterData = []): array
{
$defaultArgs = [
'perPage' => 10,
'search' => '',
'orderBy' => 'id',
'order' => 'desc',
'with_deleted' => false,
];
return array_merge($defaultArgs, $filterData);
}
private function getTipQuery(): Builder
{
return $this->getQuery()
->leftJoin('users', 'users.id', '=', "{$this->table}.waiter_id")
->leftJoin('orders', 'orders.id', '=', "{$this->table}.order_id")
->select(
"{$this->table}.id",
"{$this->table}.restaurant_id",
"{$this->table}.waiter_id",
'users.first_name as waiter_name',
"{$this->table}.order_id",
'orders.order_number as order_number',
"{$this->table}.amount",
"{$this->table}.collected_at",
"{$this->table}.status",
"{$this->table}.created_at",
"{$this->table}.updated_at",
"{$this->table}.deleted_at",
);
}
protected function filterSearchQuery(Builder|EloquentBuilder $query, string $searchedText): Builder
{
$searchable = "%$searchedText%";
return $query->where("{$this->table}.name", 'LIKE', $searchable)
->orWhere("{$this->table}.status", 'LIKE', $searchable);
}
public function getAll(array $filterData = []): Paginator
{
$filter = $this->getFilterData($filterData);
$query = $this->getTipQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
if (! empty($filter['search'])) {
$query = $this->filterSearchQuery($query, $filter['search']);
}
return $query
->orderBy($filter['orderBy'], $filter['order'])
->paginate($filter['perPage']);
}
public function getCount(array $filterData = []): int
{
$filter = $this->getFilterData($filterData);
$query = $this->getQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
return $query->count();
}
/**
* @throws Exception
*/
public function getByColumn(string $columnName, $columnValue, array $selects = ['*']): ?object
{
$item = $this->getTipQuery()
->where($columnName, $columnValue)
->first($selects);
if (empty($item)) {
throw new Exception(
$this->getExceptionMessage(static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE),
Response::HTTP_NOT_FOUND
);
}
return $item;
}
/**
* @throws Exception
*/
public function create(array $data): object
{
$data = $this->prepareForDB($data);
$id = $this->getQuery()->insertGetId($data);
return Tip::find($id);
}
/**
* @throws Exception
*/
public function update(int $id, array $data): object
{
$item = Tip::findOrFail($id);
$data = $this->prepareForDB($data, $item);
parent::update($id, $data);
return $this->getById($id);
}
/**
* @throws Exception
*/
public function prepareForDB(array $data, ?object $item = null): array
{
$data = parent::prepareForDB($data, $item);
if (empty($item)) {
$data['created_at'] = now();
$data['restaurant_id'] = $this->getCurrentRestaurantId();
} else {
if (! empty($data['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
$data['image'] = fileUploader('Accounting/', 'png', $data['image'], $item->image);
}
$data['updated_at'] = now();
}
return $data;
}
protected function getExceptionMessages(): array
{
return [
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'Tip does not exist.',
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'Tip could not be deleted.',
];
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace Modules\Accounting\Http\Controllers\API;
use App\Http\Controllers\Controller;
use Exception;
use Illuminate\Http\JsonResponse;
use Modules\Accounting\Http\Requests\Account\AccountStoreRequest;
use Modules\Accounting\Http\Requests\Account\AccountUpdateRequest;
use Modules\Accounting\Repositories\AccountRepository;
class AccountController extends Controller
{
public function __construct(private AccountRepository $repo) {}
public function index(): JsonResponse
{
try {
return $this->responseSuccess($this->repo->getAll(request()->all()), 'Account has been fetched successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function store(AccountStoreRequest $request): JsonResponse
{
try {
return $this->responseSuccess($this->repo->create($request->all()), 'Account has been created successfully.');
} catch (\Illuminate\Database\QueryException $exception) {
return $this->responseError([], 'Database error: '.$exception->getMessage());
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function show(int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->getById($id), 'Account has been fetched successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function update(AccountUpdateRequest $request, int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->update($id, $request->all()), 'Account has been updated successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function destroy(int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->delete($id), 'Account has been deleted successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace Modules\Accounting\Http\Controllers\API;
use App\Http\Controllers\Controller;
use Exception;
use Illuminate\Http\JsonResponse;
use Modules\Accounting\Http\Requests\DepositCategory\DepositCategoryStoreRequest;
use Modules\Accounting\Http\Requests\DepositCategory\DepositCategoryUpdateRequest;
use Modules\Accounting\Repositories\DepositCategoryRepository;
class DepositCategoryController extends Controller
{
public function __construct(private DepositCategoryRepository $repo) {}
public function index(): JsonResponse
{
try {
return $this->responseSuccess($this->repo->getAll(request()->all()), 'DepositCategory has been fetched successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function store(DepositCategoryStoreRequest $request): JsonResponse
{
try {
return $this->responseSuccess($this->repo->create($request->all()), 'DepositCategory has been created successfully.');
} catch (\Illuminate\Database\QueryException $exception) {
return $this->responseError([], 'Database error: '.$exception->getMessage());
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function show(int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->getById($id), 'DepositCategory has been fetched successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function update(DepositCategoryUpdateRequest $request, int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->update($id, $request->all()), 'DepositCategory has been updated successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function destroy(int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->delete($id), 'DepositCategory has been deleted successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace Modules\Accounting\Http\Controllers\API;
use App\Http\Controllers\Controller;
use Exception;
use Illuminate\Http\JsonResponse;
use Modules\Accounting\Http\Requests\Deposit\DepositStoreRequest;
use Modules\Accounting\Http\Requests\Deposit\DepositUpdateRequest;
use Modules\Accounting\Repositories\DepositRepository;
class DepositController extends Controller
{
public function __construct(private DepositRepository $repo) {}
public function index(): JsonResponse
{
try {
return $this->responseSuccess($this->repo->getAll(request()->all()), 'Deposit has been fetched successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function store(DepositStoreRequest $request): JsonResponse
{
try {
return $this->responseSuccess($this->repo->create($request->all()), 'Deposit has been created successfully.');
} catch (\Illuminate\Database\QueryException $exception) {
return $this->responseError([], 'Database error: '.$exception->getMessage());
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function show(int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->getById($id), 'Deposit has been fetched successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function update(DepositUpdateRequest $request, int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->update($id, $request->all()), 'Deposit has been updated successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function destroy(int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->delete($id), 'Deposit has been deleted successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace Modules\Accounting\Http\Controllers\API;
use App\Http\Controllers\Controller;
use Exception;
use Illuminate\Http\JsonResponse;
use Modules\Accounting\Http\Requests\ExpenseCategory\ExpenseCategoryStoreRequest;
use Modules\Accounting\Http\Requests\ExpenseCategory\ExpenseCategoryUpdateRequest;
use Modules\Accounting\Repositories\ExpenseCategoryRepository;
class ExpenseCategoryController extends Controller
{
public function __construct(private ExpenseCategoryRepository $repo) {}
public function index(): JsonResponse
{
try {
return $this->responseSuccess($this->repo->getAll(request()->all()), 'ExpenseCategory has been fetched successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function store(ExpenseCategoryStoreRequest $request): JsonResponse
{
try {
return $this->responseSuccess($this->repo->create($request->all()), 'ExpenseCategory has been created successfully.');
} catch (\Illuminate\Database\QueryException $exception) {
return $this->responseError([], 'Database error: '.$exception->getMessage());
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function show(int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->getById($id), 'ExpenseCategory has been fetched successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function update(ExpenseCategoryUpdateRequest $request, int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->update($id, $request->all()), 'ExpenseCategory has been updated successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function destroy(int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->delete($id), 'ExpenseCategory has been deleted successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace Modules\Accounting\Http\Controllers\API;
use App\Http\Controllers\Controller;
use Exception;
use Illuminate\Http\JsonResponse;
use Modules\Accounting\Http\Requests\Expense\ExpenseStoreRequest;
use Modules\Accounting\Http\Requests\Expense\ExpenseUpdateRequest;
use Modules\Accounting\Repositories\ExpenseRepository;
class ExpenseController extends Controller
{
public function __construct(private ExpenseRepository $repo) {}
public function index(): JsonResponse
{
try {
return $this->responseSuccess($this->repo->getAll(request()->all()), 'Expense has been fetched successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function store(ExpenseStoreRequest $request): JsonResponse
{
try {
return $this->responseSuccess($this->repo->create($request->all()), 'Expense has been created successfully.');
} catch (\Illuminate\Database\QueryException $exception) {
return $this->responseError([], 'Database error: '.$exception->getMessage());
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function show(int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->getById($id), 'Expense has been fetched successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function update(ExpenseUpdateRequest $request, int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->update($id, $request->all()), 'Expense has been updated successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function destroy(int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->delete($id), 'Expense has been deleted successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace Modules\Accounting\Http\Controllers\API;
use App\Http\Controllers\Controller;
use Exception;
use Illuminate\Http\JsonResponse;
use Modules\Accounting\Http\Requests\Fund\FundStoreRequest;
use Modules\Accounting\Http\Requests\Fund\FundUpdateRequest;
use Modules\Accounting\Repositories\FundRepository;
class FundController extends Controller
{
public function __construct(private FundRepository $repo) {}
public function index(): JsonResponse
{
try {
return $this->responseSuccess($this->repo->getAll(request()->all()), 'Fund has been fetched successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function store(FundStoreRequest $request): JsonResponse
{
try {
return $this->responseSuccess($this->repo->create($request->all()), 'Fund has been created successfully.');
} catch (\Illuminate\Database\QueryException $exception) {
return $this->responseError([], 'Database error: '.$exception->getMessage());
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function show(int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->getById($id), 'Fund has been fetched successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function update(FundUpdateRequest $request, int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->update($id, $request->all()), 'Fund has been updated successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function destroy(int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->delete($id), 'Fund has been deleted successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace Modules\Accounting\Http\Controllers\API;
use App\Http\Controllers\Controller;
use Exception;
use Illuminate\Http\JsonResponse;
use Modules\Accounting\Http\Requests\FundTransfer\FundTransferStoreRequest;
use Modules\Accounting\Http\Requests\FundTransfer\FundTransferUpdateRequest;
use Modules\Accounting\Repositories\FundTransferRepository;
class FundTransferController extends Controller
{
public function __construct(private FundTransferRepository $repo) {}
public function index(): JsonResponse
{
try {
return $this->responseSuccess($this->repo->getAll(request()->all()), 'FundTransfer has been fetched successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function store(FundTransferStoreRequest $request): JsonResponse
{
try {
return $this->responseSuccess($this->repo->create($request->all()), 'FundTransfer has been created successfully.');
} catch (\Illuminate\Database\QueryException $exception) {
return $this->responseError([], 'Database error: '.$exception->getMessage());
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function show(int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->getById($id), 'FundTransfer has been fetched successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function update(FundTransferUpdateRequest $request, int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->update($id, $request->all()), 'FundTransfer has been updated successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function destroy(int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->delete($id), 'FundTransfer has been deleted successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace Modules\Accounting\Http\Controllers\API;
use App\Http\Controllers\Controller;
use Exception;
use Illuminate\Http\JsonResponse;
use Modules\Accounting\Http\Requests\Tip\TipStoreRequest;
use Modules\Accounting\Http\Requests\Tip\TipUpdateRequest;
use Modules\Accounting\Repositories\TipRepository;
class TipController extends Controller
{
public function __construct(private TipRepository $repo) {}
public function index(): JsonResponse
{
try {
return $this->responseSuccess($this->repo->getAll(request()->all()), 'Tip has been fetched successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function store(TipStoreRequest $request): JsonResponse
{
try {
return $this->responseSuccess($this->repo->create($request->all()), 'Tip has been created successfully.');
} catch (\Illuminate\Database\QueryException $exception) {
return $this->responseError([], 'Database error: '.$exception->getMessage());
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function show(int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->getById($id), 'Tip has been fetched successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function update(TipUpdateRequest $request, int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->update($id, $request->all()), 'Tip has been updated successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function destroy(int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->delete($id), 'Tip has been deleted successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace Modules\Accounting\Http\Controllers\API;
use App\Http\Controllers\Controller;
use Exception;
use Illuminate\Http\JsonResponse;
use Modules\Accounting\Http\Requests\TipDistribution\TipDistributionStoreRequest;
use Modules\Accounting\Http\Requests\TipDistribution\TipDistributionUpdateRequest;
use Modules\Accounting\Repositories\TipDistributionRepository;
class TipDistributionController extends Controller
{
public function __construct(private TipDistributionRepository $repo) {}
public function index(): JsonResponse
{
try {
return $this->responseSuccess($this->repo->getAll(request()->all()), 'TipDistribution has been fetched successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function store(TipDistributionStoreRequest $request): JsonResponse
{
try {
return $this->responseSuccess($this->repo->create($request->all()), 'TipDistribution has been created successfully.');
} catch (\Illuminate\Database\QueryException $exception) {
return $this->responseError([], 'Database error: '.$exception->getMessage());
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function show(int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->getById($id), 'TipDistribution has been fetched successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function update(TipDistributionUpdateRequest $request, int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->update($id, $request->all()), 'TipDistribution has been updated successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
public function destroy(int $id): JsonResponse
{
try {
return $this->responseSuccess($this->repo->delete($id), 'TipDistribution has been deleted successfully.');
} catch (Exception $e) {
return $this->responseError([], $e->getMessage());
}
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Modules\Accounting\Http\Requests\Account;
use Illuminate\Foundation\Http\FormRequest;
class AccountStoreRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => 'required|string|max:255',
'code' => ['nullable', 'string', 'max:50'],
'type' => 'required|in:asset,liability,equity,income,expense',
'opening_balance' => 'nullable|numeric|min:0',
'current_balance' => 'nullable|numeric|min:0',
'status' => 'nullable|in:0,1',
];
}
public function authorize(): bool
{
return true;
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Modules\Accounting\Http\Requests\Account;
use Illuminate\Foundation\Http\FormRequest;
class AccountUpdateRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => 'required|string|max:255',
'code' => ['nullable', 'string', 'max:50'],
'type' => 'required|in:asset,liability,equity,income,expense',
'opening_balance' => 'nullable|numeric|min:0',
'current_balance' => 'nullable|numeric|min:0',
'status' => 'nullable|in:0,1',
];
}
public function authorize(): bool
{
return true;
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace Modules\Accounting\Http\Requests\Deposit;
use Illuminate\Foundation\Http\FormRequest;
class DepositStoreRequest extends FormRequest
{
public function rules(): array
{
return [
'fund_id' => 'required|exists:funds,id',
'account_id' => 'nullable|exists:accounts,id',
'amount' => 'required|numeric|min:0.01',
'transaction_date' => 'required|date',
'received_from' => 'nullable|string|max:255',
'note' => 'nullable|string',
'created_by' => 'nullable|exists:users,id',
'status' => 'nullable|in:0,1',
];
}
public function authorize(): bool
{
return true;
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Modules\Accounting\Http\Requests\Deposit;
use Illuminate\Foundation\Http\FormRequest;
class DepositUpdateRequest extends FormRequest
{
public function rules(): array
{
$depositId = $this->route('deposit');
return [
'fund_id' => 'required|exists:funds,id',
'account_id' => 'nullable|exists:accounts,id',
'amount' => 'required|numeric|min:0.01',
'transaction_date' => 'required|date',
'received_from' => 'nullable|string|max:255',
'note' => 'nullable|string',
'created_by' => 'nullable|exists:users,id',
'status' => 'nullable|in:0,1',
];
}
public function authorize(): bool
{
return true;
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Modules\Accounting\Http\Requests\DepositCategory;
use Illuminate\Foundation\Http\FormRequest;
class DepositCategoryStoreRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => 'required|string|max:255',
'status' => 'nullable|in:0,1',
];
}
public function authorize(): bool
{
return true;
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Modules\Accounting\Http\Requests\DepositCategory;
use Illuminate\Foundation\Http\FormRequest;
class DepositCategoryUpdateRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => 'required|string|max:255',
'status' => 'nullable|in:0,1',
];
}
public function authorize(): bool
{
return true;
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Modules\Accounting\Http\Requests\Expense;
use Illuminate\Foundation\Http\FormRequest;
class ExpenseStoreRequest extends FormRequest
{
public function rules(): array
{
return [
'account_id' => 'required|exists:accounts,id',
'expense_category_id' => 'nullable|exists:expense_categories,id',
'amount' => 'required|numeric|min:0.01',
'transaction_date' => 'required|date',
'details' => 'nullable|string',
'created_by' => 'nullable|exists:users,id',
'status' => 'nullable|in:0,1',
];
}
public function authorize(): bool
{
return true;
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace Modules\Accounting\Http\Requests\Expense;
use Illuminate\Foundation\Http\FormRequest;
class ExpenseUpdateRequest extends FormRequest
{
public function rules(): array
{
$expenseId = $this->route('expense');
return [
'account_id' => 'required|exists:accounts,id',
'expense_category_id' => 'nullable|exists:expense_categories,id',
'amount' => 'required|numeric|min:0.01',
'transaction_date' => 'required|date',
'details' => 'nullable|string',
'created_by' => 'nullable|exists:users,id',
'status' => 'nullable|in:0,1',
];
}
public function authorize(): bool
{
return true;
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Modules\Accounting\Http\Requests\ExpenseCategory;
use Illuminate\Foundation\Http\FormRequest;
class ExpenseCategoryStoreRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => 'required|string|max:255',
'status' => 'nullable|in:0,1',
];
}
public function authorize(): bool
{
return true;
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Modules\Accounting\Http\Requests\ExpenseCategory;
use Illuminate\Foundation\Http\FormRequest;
class ExpenseCategoryUpdateRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => 'required|string|max:255',
'status' => 'nullable|in:0,1',
];
}
public function authorize(): bool
{
return true;
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Modules\Accounting\Http\Requests\Fund;
use Illuminate\Foundation\Http\FormRequest;
class FundStoreRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => 'required|string|max:255',
'code' => ['nullable', 'string', 'max:50'],
'type' => 'required|in:asset,liability,equity,income,expense',
'opening_balance' => 'nullable|numeric|min:0',
'current_balance' => 'nullable|numeric|min:0',
'is_default' => 'boolean',
'status' => 'nullable|in:0,1',
];
}
public function authorize(): bool
{
return true;
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Modules\Accounting\Http\Requests\Fund;
use Illuminate\Foundation\Http\FormRequest;
class FundUpdateRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => 'required|string|max:255',
'code' => ['nullable', 'string', 'max:50'],
'type' => 'required|in:asset,liability,equity,income,expense',
'opening_balance' => 'nullable|numeric|min:0',
'current_balance' => 'nullable|numeric|min:0',
'is_default' => 'boolean',
'status' => 'nullable|in:0,1',
];
}
public function authorize(): bool
{
return true;
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace Modules\Accounting\Http\Requests\FundTransfer;
use Illuminate\Foundation\Http\FormRequest;
class FundTransferStoreRequest extends FormRequest
{
public function rules(): array
{
return [
'from_fund_id' => 'required|exists:funds,id',
'to_fund_id' => 'required|exists:funds,id|different:from_fund_id',
'amount' => 'required|numeric|min:0.01',
'transfer_date' => 'required|date',
'note' => 'nullable|string',
'created_by' => 'nullable|exists:users,id',
'status' => 'nullable|in:0,1',
];
}
public function messages(): array
{
return [
'to_fund_id.different' => 'Destination fund must be different from source fund.',
];
}
public function authorize(): bool
{
return true;
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace Modules\Accounting\Http\Requests\FundTransfer;
use Illuminate\Foundation\Http\FormRequest;
class FundTransferUpdateRequest extends FormRequest
{
public function rules(): array
{
$transferId = $this->route('fund_transfer');
return [
'from_fund_id' => 'required|exists:funds,id',
'to_fund_id' => 'required|exists:funds,id|different:from_fund_id',
'amount' => 'required|numeric|min:0.01',
'transfer_date' => 'required|date',
'note' => 'nullable|string',
'created_by' => 'nullable|exists:users,id',
'status' => 'nullable|in:0,1',
];
}
public function messages(): array
{
return [
'to_fund_id.different' => 'Destination fund must be different from source fund.',
];
}
public function authorize(): bool
{
return true;
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace Modules\Accounting\Http\Requests\Tip;
use Illuminate\Foundation\Http\FormRequest;
class TipStoreRequest extends FormRequest
{
public function rules(): array
{
return [
'waiter_id' => 'required|exists:users,id',
'order_id' => 'nullable|exists:orders,id',
'amount' => 'required|numeric|min:0.01',
'collected_at' => 'nullable|date',
'status' => 'nullable|in:0,1',
];
}
public function authorize(): bool
{
return true;
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Modules\Accounting\Http\Requests\Tip;
use Illuminate\Foundation\Http\FormRequest;
class TipUpdateRequest extends FormRequest
{
public function rules(): array
{
$tipId = $this->route('tip');
return [
'waiter_id' => 'required|exists:users,id',
'order_id' => 'nullable|exists:orders,id',
'amount' => 'required|numeric|min:0.01',
'collected_at' => 'nullable|date',
'status' => 'nullable|in:0,1',
];
}
public function authorize(): bool
{
return true;
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Modules\Accounting\Http\Requests\TipDistribution;
use Illuminate\Foundation\Http\FormRequest;
class TipDistributionStoreRequest extends FormRequest
{
public function rules(): array
{
return [
'waiter_id' => 'required|exists:users,id',
'account_id' => 'required|exists:accounts,id',
'amount' => 'required|numeric|min:0.01',
'distributed_at' => 'nullable|date',
'created_by' => 'nullable|exists:users,id',
'status' => 'nullable|in:0,1',
];
}
public function authorize(): bool
{
return true;
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace Modules\Accounting\Http\Requests\TipDistribution;
use Illuminate\Foundation\Http\FormRequest;
class TipDistributionUpdateRequest extends FormRequest
{
public function rules(): array
{
$distributionId = $this->route('tip_distribution');
return [
'waiter_id' => 'required|exists:users,id',
'account_id' => 'required|exists:accounts,id',
'amount' => 'required|numeric|min:0.01',
'distributed_at' => 'nullable|date',
'created_by' => 'nullable|exists:users,id',
'status' => 'nullable|in:0,1',
];
}
public function authorize(): bool
{
return true;
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace Modules\Accounting\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Account extends Model
{
protected $fillable = [
'restaurant_id',
'name',
'code',
'type',
'opening_balance',
'current_balance',
'status',
];
public const TABLE_NAME = 'accounts';
protected $table = self::TABLE_NAME;
public function transactionDetails(): HasMany
{
return $this->hasMany(TransactionDetail::class);
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace Modules\Accounting\Models;
use Illuminate\Database\Eloquent\Model;
class Deposit extends Model
{
protected $fillable = [
'restaurant_id',
'fund_id',
'account_id',
'deposit_category_id',
'amount',
'transaction_date',
'voucher_no',
'received_from',
'note',
'created_by',
'status',
];
protected $dates = ['transaction_date'];
public const TABLE_NAME = 'deposits';
protected $table = self::TABLE_NAME;
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Modules\Accounting\Models;
use Illuminate\Database\Eloquent\Model;
class DepositCategory extends Model
{
protected $fillable = [
'restaurant_id',
'name',
'status',
'created_at',
'updated_at',
'deleted_at',
];
public const TABLE_NAME = 'deposit_categories';
protected $table = self::TABLE_NAME;
}

View File

@@ -0,0 +1,28 @@
<?php
namespace Modules\Accounting\Models;
use Illuminate\Database\Eloquent\Model;
class Expense extends Model
{
protected $fillable = [
'restaurant_id',
'fund_id',
'account_id',
'expense_category_id',
'amount',
'transaction_date',
'voucher_no',
'received_from',
'note',
'created_by',
'status',
];
protected $dates = ['transaction_date'];
public const TABLE_NAME = 'expenses';
protected $table = self::TABLE_NAME;
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Modules\Accounting\Models;
use Illuminate\Database\Eloquent\Model;
class ExpenseCategory extends Model
{
protected $fillable = [
'restaurant_id',
'name',
'status',
'created_at',
'updated_at',
'deleted_at',
];
public const TABLE_NAME = 'expense_categories';
protected $table = self::TABLE_NAME;
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Modules\Accounting\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Fund extends Model
{
protected $fillable = [
'restaurant_id',
'name',
'type',
'code',
'opening_balance',
'current_balance',
'is_default',
'status',
];
public const TABLE_NAME = 'funds';
protected $table = self::TABLE_NAME;
public function transactions(): HasMany
{
return $this->hasMany(Transaction::class);
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace Modules\Accounting\Models;
use Illuminate\Database\Eloquent\Model;
class FundTransfer extends Model
{
protected $fillable = [
'restaurant_id',
'from_fund_id',
'to_fund_id',
'amount',
'note',
'created_by',
'transfer_date',
];
protected $dates = ['transfer_date'];
public const TABLE_NAME = 'fund_transfers';
protected $table = self::TABLE_NAME;
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Modules\Accounting\Models;
use Illuminate\Database\Eloquent\Model;
class Tip extends Model
{
protected $fillable = [
'restaurant_id',
'waiter_id',
'order_id',
'amount',
'collected_at',
'status',
'created_at',
'updated_at',
'deleted_at',
];
protected $dates = ['collected_at'];
public const TABLE_NAME = 'tips';
protected $table = self::TABLE_NAME;
}

View File

@@ -0,0 +1,28 @@
<?php
namespace Modules\Accounting\Models;
use Illuminate\Database\Eloquent\Model;
class TipDistribution extends Model
{
protected $fillable = [
'restaurant_id',
'waiter_id',
'account_id',
'amount',
'created_by',
'distributed_at',
'status',
'created_by',
'created_at',
'updated_at',
'deleted_at',
];
protected $dates = ['distributed_at'];
public const TABLE_NAME = 'tip_distributions';
protected $table = self::TABLE_NAME;
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Modules\Accounting\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Transaction extends Model
{
protected $fillable = [
'restaurant_id',
'fund_id',
'transaction_type',
'transaction_date',
'reference_no',
'notes',
'total_debit',
'total_credit',
'created_by',
];
protected $dates = ['transaction_date'];
public const TABLE_NAME = 'transactions';
protected $table = self::TABLE_NAME;
public function details(): HasMany
{
return $this->hasMany(TransactionDetail::class);
}
public function fund(): BelongsTo
{
return $this->belongsTo(Fund::class);
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace Modules\Accounting\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class TransactionDetail extends Model
{
protected $fillable = [
'restaurant_id',
'transaction_id',
'account_id',
'debit',
'credit',
'note',
];
public const TABLE_NAME = 'transaction_details';
protected $table = self::TABLE_NAME;
public function account(): BelongsTo
{
return $this->belongsTo(Account::class);
}
public function transaction(): BelongsTo
{
return $this->belongsTo(Transaction::class);
}
}

View File

@@ -0,0 +1,154 @@
<?php
namespace Modules\Accounting\Providers;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
use Nwidart\Modules\Traits\PathNamespace;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
class AccountingServiceProvider extends ServiceProvider
{
use PathNamespace;
protected string $name = 'Accounting';
protected string $nameLower = 'accounting';
/**
* Boot the application events.
*/
public function boot(): void
{
$this->registerCommands();
$this->registerCommandSchedules();
$this->registerTranslations();
$this->registerConfig();
$this->registerViews();
$this->loadMigrationsFrom(module_path($this->name, 'database/migrations'));
}
/**
* Register the service provider.
*/
public function register(): void
{
$this->app->register(EventServiceProvider::class);
$this->app->register(RouteServiceProvider::class);
}
/**
* Register commands in the format of Command::class
*/
protected function registerCommands(): void
{
// $this->commands([]);
}
/**
* Register command Schedules.
*/
protected function registerCommandSchedules(): void
{
// $this->app->booted(function () {
// $schedule = $this->app->make(Schedule::class);
// $schedule->command('inspire')->hourly();
// });
}
/**
* Register translations.
*/
public function registerTranslations(): void
{
$langPath = resource_path('lang/modules/'.$this->nameLower);
if (is_dir($langPath)) {
$this->loadTranslationsFrom($langPath, $this->nameLower);
$this->loadJsonTranslationsFrom($langPath);
} else {
$this->loadTranslationsFrom(module_path($this->name, 'lang'), $this->nameLower);
$this->loadJsonTranslationsFrom(module_path($this->name, 'lang'));
}
}
/**
* Register config.
*/
protected function registerConfig(): void
{
$configPath = module_path($this->name, config('modules.paths.generator.config.path'));
if (is_dir($configPath)) {
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($configPath));
foreach ($iterator as $file) {
if ($file->isFile() && $file->getExtension() === 'php') {
$config = str_replace($configPath.DIRECTORY_SEPARATOR, '', $file->getPathname());
$config_key = str_replace([DIRECTORY_SEPARATOR, '.php'], ['.', ''], $config);
$segments = explode('.', $this->nameLower.'.'.$config_key);
// Remove duplicated adjacent segments
$normalized = [];
foreach ($segments as $segment) {
if (end($normalized) !== $segment) {
$normalized[] = $segment;
}
}
$key = ($config === 'config.php') ? $this->nameLower : implode('.', $normalized);
$this->publishes([$file->getPathname() => config_path($config)], 'config');
$this->merge_config_from($file->getPathname(), $key);
}
}
}
}
/**
* Merge config from the given path recursively.
*/
protected function merge_config_from(string $path, string $key): void
{
$existing = config($key, []);
$module_config = require $path;
config([$key => array_replace_recursive($existing, $module_config)]);
}
/**
* Register views.
*/
public function registerViews(): void
{
$viewPath = resource_path('views/modules/'.$this->nameLower);
$sourcePath = module_path($this->name, 'resources/views');
$this->publishes([$sourcePath => $viewPath], ['views', $this->nameLower.'-module-views']);
$this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->nameLower);
Blade::componentNamespace(config('modules.namespace').'\\'.$this->name.'\\View\\Components', $this->nameLower);
}
/**
* Get the services provided by the provider.
*/
public function provides(): array
{
return [];
}
private function getPublishableViewPaths(): array
{
$paths = [];
foreach (config('view.paths') as $path) {
if (is_dir($path.'/modules/'.$this->nameLower)) {
$paths[] = $path.'/modules/'.$this->nameLower;
}
}
return $paths;
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace Modules\Accounting\Providers;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event handler mappings for the application.
*
* @var array<string, array<int, string>>
*/
protected $listen = [];
/**
* Indicates if events should be discovered.
*
* @var bool
*/
protected static $shouldDiscoverEvents = true;
/**
* Configure the proper event listeners for email verification.
*/
protected function configureEmailVerification(): void {}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace Modules\Accounting\Providers;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
protected string $name = 'Accounting';
/**
* Called before routes are registered.
*
* Register any model bindings or pattern based filters.
*/
public function boot(): void
{
parent::boot();
}
/**
* Define the routes for the application.
*/
public function map(): void
{
$this->mapApiRoutes();
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*/
protected function mapApiRoutes(): void
{
Route::middleware('api')->prefix('api')->name('api.')->group(module_path($this->name, '/routes/api.php'));
}
}

View File

@@ -0,0 +1,30 @@
{
"name": "nwidart/accounting",
"description": "",
"authors": [
{
"name": "Nicolas Widart",
"email": "n.widart@gmail.com"
}
],
"extra": {
"laravel": {
"providers": [],
"aliases": {
}
}
},
"autoload": {
"psr-4": {
"Modules\\Accounting\\": "app/",
"Modules\\Accounting\\Database\\Factories\\": "database/factories/",
"Modules\\Accounting\\Database\\Seeders\\": "database/seeders/"
}
},
"autoload-dev": {
"psr-4": {
"Modules\\Accounting\\Tests\\": "tests/"
}
}
}

View File

@@ -0,0 +1,5 @@
<?php
return [
'name' => 'Accounting',
];

View File

@@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('accounts', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('restaurant_id')->nullable();
$table->string('name');
$table->string('code')->nullable();
$table->enum('type', ['asset', 'liability', 'equity', 'income', 'expense'])->default('asset');
$table->decimal('opening_balance', 15, 2)->default(0);
$table->decimal('current_balance', 15, 2)->default(0);
$table->smallInteger('status')->default(1)->comment('1=Active, 2=InActive');
$table->timestamps();
$table->softDeletes();
});
}
public function down(): void
{
Schema::dropIfExists('accounts');
}
};

View File

@@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('funds', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('restaurant_id')->nullable();
$table->string('name');
$table->enum('type', ['asset', 'liability', 'equity', 'income', 'expense'])->default('asset');
$table->string('code')->nullable();
$table->decimal('opening_balance', 15, 2)->default(0);
$table->decimal('current_balance', 15, 2)->default(0);
$table->boolean('is_default')->default(false);
$table->smallInteger('status')->default(1)->comment('1=Active, 2=InActive');
$table->timestamps();
$table->softDeletes();
});
}
public function down(): void
{
Schema::dropIfExists('funds');
}
};

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('transactions', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('restaurant_id')->nullable();
$table->unsignedBigInteger('fund_id')->nullable()->index();
$table->string('transaction_type'); // deposit, payment, journal, sale, purchase, loan, transfer, tip
$table->date('transaction_date')->index();
$table->string('reference_no')->nullable()->index();
$table->text('notes')->nullable();
$table->decimal('total_debit', 15, 2)->default(0);
$table->decimal('total_credit', 15, 2)->default(0);
$table->unsignedBigInteger('created_by')->nullable();
$table->smallInteger('status')->default(1)->comment('1=Active, 2=InActive');
$table->timestamps();
$table->softDeletes();
});
}
public function down(): void
{
Schema::dropIfExists('transactions');
}
};

View File

@@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('transaction_details', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('restaurant_id')->nullable();
$table->unsignedBigInteger('transaction_id')->index();
$table->unsignedBigInteger('account_id')->index();
$table->decimal('debit', 15, 2)->default(0);
$table->decimal('credit', 15, 2)->default(0);
$table->text('note')->nullable();
$table->smallInteger('status')->default(1)->comment('1=Active, 2=InActive');
$table->timestamps();
$table->softDeletes();
});
}
public function down(): void
{
Schema::dropIfExists('transaction_details');
}
};

View File

@@ -0,0 +1,25 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('expense_categories', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('restaurant_id')->nullable();
$table->string('name');
$table->smallInteger('status')->default(1)->comment('1=Active, 2=InActive');
$table->timestamps();
$table->softDeletes();
});
}
public function down(): void
{
Schema::dropIfExists('expense_categories');
}
};

View File

@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('expenses', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('restaurant_id')->nullable();
$table->unsignedBigInteger('fund_id')->index(); // where money arrived
$table->unsignedBigInteger('account_id')->index(); // account used to pay
$table->unsignedBigInteger('expense_category_id')->nullable()->index();
$table->decimal('amount', 15, 2);
$table->date('transaction_date')->index();
$table->string('voucher_no')->nullable();
$table->string('received_from')->nullable();
$table->text('note')->nullable();
$table->unsignedBigInteger('created_by')->nullable();
$table->smallInteger('status')->default(1)->comment('1=Active, 2=InActive');
$table->timestamps();
$table->softDeletes();
});
}
public function down(): void
{
Schema::dropIfExists('expenses');
}
};

View File

@@ -0,0 +1,25 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('deposit_categories', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('restaurant_id')->nullable();
$table->string('name');
$table->smallInteger('status')->default(1)->comment('1=Active, 2=InActive');
$table->timestamps();
$table->softDeletes();
});
}
public function down(): void
{
Schema::dropIfExists('deposit_categories');
}
};

View File

@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('deposits', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('restaurant_id')->nullable();
$table->unsignedBigInteger('fund_id')->index(); // where money arrived
$table->unsignedBigInteger('account_id')->index(); // source account (if any)
$table->unsignedBigInteger('deposit_category_id')->nullable()->index();
$table->decimal('amount', 15, 2);
$table->date('transaction_date')->index();
$table->string('voucher_no')->nullable();
$table->string('received_from')->nullable();
$table->text('note')->nullable();
$table->unsignedBigInteger('created_by')->nullable();
$table->smallInteger('status')->default(1)->comment('1=Active, 2=InActive');
$table->timestamps();
$table->softDeletes();
});
}
public function down(): void
{
Schema::dropIfExists('deposits');
}
};

View File

@@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('fund_transfers', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('restaurant_id')->nullable();
$table->unsignedBigInteger('from_fund_id')->index();
$table->unsignedBigInteger('to_fund_id')->index();
$table->decimal('amount', 15, 2);
$table->text('note')->nullable();
$table->unsignedBigInteger('created_by')->nullable();
$table->date('transfer_date')->index();
$table->smallInteger('status')->default(1)->comment('1=Active, 2=InActive');
$table->timestamps();
$table->softDeletes();
});
}
public function down(): void
{
Schema::dropIfExists('fund_transfers');
}
};

View File

@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('tips', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('restaurant_id')->nullable();
$table->unsignedBigInteger('waiter_id')->nullable()->index();
$table->unsignedBigInteger('order_id')->nullable()->index();
$table->decimal('amount', 15, 2)->default(0);
$table->date('collected_at')->nullable();
$table->smallInteger('status')->default(1)->comment('1=Active, 2=InActive');
$table->timestamps();
$table->softDeletes();
});
}
public function down(): void
{
Schema::dropIfExists('tips');
}
};

View File

@@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('tip_distributions', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('restaurant_id')->nullable();
$table->unsignedBigInteger('waiter_id')->index();
$table->unsignedBigInteger('account_id')->index();
$table->decimal('amount', 15, 2);
$table->unsignedBigInteger('created_by')->nullable();
$table->date('distributed_at')->nullable();
$table->smallInteger('status')->default(1)->comment('1=Active, 2=InActive');
$table->timestamps();
$table->softDeletes();
});
}
public function down(): void
{
Schema::dropIfExists('tip_distributions');
}
};

View File

@@ -0,0 +1,23 @@
<?php
namespace Modules\Accounting\Database\Seeders;
use Illuminate\Database\Seeder;
class AccountingDatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$this->call([
AccountingSeeder::class,
FundSeeder::class,
DepositCategorySeeder::class,
ExpenseCategorySeeder::class,
DepositSeeder::class,
ExpenseSeeder::class,
]);
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace Modules\Accounting\Database\Seeders;
use Illuminate\Database\Seeder;
use Modules\Accounting\Models\Account;
class AccountingSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
// In SaaS onboarding, dynamic restaurant id assigned.
// For now, making example default:
$restaurantId = 1;
/*
|--------------------------------------------------------------------------
| DEFAULT ACCOUNTS (Chart of Accounts)
|--------------------------------------------------------------------------
*/
$defaultAccounts = [
['name' => 'Cash', 'type' => 'asset', 'code' => 'AC-001'],
['name' => 'Bank', 'type' => 'asset', 'code' => 'AC-002'],
['name' => 'Loan Receivable', 'type' => 'asset', 'code' => 'AC-003'],
['name' => 'Sales', 'type' => 'income', 'code' => 'AC-101'],
['name' => 'Purchase', 'type' => 'expense', 'code' => 'AC-201'],
['name' => 'Operating Expense', 'type' => 'expense', 'code' => 'AC-202'],
['name' => 'Loan Payable', 'type' => 'liability', 'code' => 'AC-301'],
['name' => 'Tips Received', 'type' => 'liability', 'code' => 'AC-302'],
];
foreach ($defaultAccounts as $acc) {
Account::updateOrCreate(
[
'restaurant_id' => $restaurantId,
'code' => $acc['code'],
],
[
'name' => $acc['name'],
'type' => $acc['type'],
'opening_balance' => 0,
'current_balance' => 0,
'status' => 1,
]
);
}
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace Modules\Accounting\Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class DepositCategorySeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
DB::table('deposit_categories')->insert([
['restaurant_id' => 1, 'name' => 'Customer Payment'],
['restaurant_id' => 1, 'name' => 'Fund Transfer In'],
['restaurant_id' => 1, 'name' => 'Sales Revenue'],
['restaurant_id' => 1, 'name' => 'Donations'],
['restaurant_id' => 1, 'name' => 'Loan Received'],
['restaurant_id' => 1, 'name' => 'Service Charge'],
]);
}
}

View File

@@ -0,0 +1,118 @@
<?php
namespace Modules\Accounting\Database\Seeders;
use Carbon\Carbon;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Modules\Accounting\Models\Account;
use Modules\Accounting\Models\Deposit;
use Modules\Accounting\Models\Fund;
use Modules\Accounting\Models\Transaction;
use Modules\Accounting\Models\TransactionDetail;
class DepositSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$restaurantId = 1; // example restaurant
// Sample Deposit Data
$deposits = [
[
'fund_name' => 'Cash', // fund where money arrived
'account_code' => 'AC-101', // source account (income/sales)
'amount' => 500.00,
'transaction_date' => Carbon::now()->subDays(2),
'voucher_no' => 'DEP-001',
'received_from' => 'Customer A',
'note' => 'Cash sale deposit',
'created_by' => 1,
],
[
'fund_name' => 'Bank',
'account_code' => 'AC-101',
'amount' => 1000.00,
'transaction_date' => Carbon::now()->subDay(),
'voucher_no' => 'DEP-002',
'received_from' => 'Customer B',
'note' => 'Bank deposit from sales',
'created_by' => 1,
],
];
foreach ($deposits as $dep) {
$fund = Fund::where('restaurant_id', $restaurantId)
->where('name', $dep['fund_name'])
->first();
$account = Account::where('restaurant_id', $restaurantId)
->where('code', $dep['account_code'])
->first();
if (! $fund || ! $account) {
continue;
}
DB::transaction(function () use ($restaurantId, $fund, $account, $dep) {
// 1⃣ Create Deposit
$deposit = Deposit::create([
'restaurant_id' => $restaurantId,
'fund_id' => $fund->id,
'account_id' => $account->id,
'deposit_category_id' => 1,
'amount' => $dep['amount'],
'transaction_date' => $dep['transaction_date'],
'voucher_no' => $dep['voucher_no'],
'received_from' => $dep['received_from'],
'note' => $dep['note'],
'created_by' => $dep['created_by'],
'status' => 1,
]);
// 2⃣ Create Transaction
$transaction = Transaction::create([
'restaurant_id' => $restaurantId,
'fund_id' => $fund->id,
'transaction_type' => 'deposit',
'transaction_date' => $dep['transaction_date'],
'reference_no' => $dep['voucher_no'],
'notes' => $dep['note'],
'total_debit' => 0,
'total_credit' => $dep['amount'],
'created_by' => $dep['created_by'],
'status' => 1,
]);
// 3⃣ Transaction Details
// Credit to Fund (increase)
TransactionDetail::create([
'restaurant_id' => $restaurantId,
'transaction_id' => $transaction->id,
'account_id' => $fund->id, // fund receives money (asset)
'debit' => $dep['amount'],
'credit' => 0,
'note' => $dep['note'].' (Fund)',
'status' => 1,
]);
// Debit from Source Account
TransactionDetail::create([
'restaurant_id' => $restaurantId,
'transaction_id' => $transaction->id,
'account_id' => $account->id, // source account (income)
'debit' => 0,
'credit' => $dep['amount'],
'note' => $dep['note'].' (Source Account)',
'status' => 1,
]);
// 4⃣ Update Fund Balance
$fund->increment('current_balance', $dep['amount']);
});
}
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Modules\Accounting\Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class ExpenseCategorySeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
DB::table('expense_categories')->insert([
['restaurant_id' => 1, 'name' => 'Food Purchase'],
['restaurant_id' => 1, 'name' => 'Operating Expense'],
['restaurant_id' => 1, 'name' => 'Salaries'],
['restaurant_id' => 1, 'name' => 'Marketing'],
['restaurant_id' => 1, 'name' => 'Electricity Bill'],
['restaurant_id' => 1, 'name' => 'Loan Repayment'],
['restaurant_id' => 1, 'name' => 'Fund Transfer Out'],
]);
}
}

View File

@@ -0,0 +1,118 @@
<?php
namespace Modules\Accounting\Database\Seeders;
use Carbon\Carbon;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Modules\Accounting\Models\Account;
use Modules\Accounting\Models\Expense;
use Modules\Accounting\Models\Fund;
use Modules\Accounting\Models\Transaction;
use Modules\Accounting\Models\TransactionDetail;
class ExpenseSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$restaurantId = 1; // example restaurant
// Sample Expense Data
$expenses = [
[
'fund_name' => 'Cash', // fund where money arrived
'account_code' => 'AC-101', // source account (income/sales)
'amount' => 500.00,
'transaction_date' => Carbon::now()->subDays(2),
'voucher_no' => 'DEP-001',
'received_from' => 'Customer A',
'note' => 'Cash sale expense',
'created_by' => 1,
],
[
'fund_name' => 'Bank',
'account_code' => 'AC-101',
'amount' => 1000.00,
'transaction_date' => Carbon::now()->subDay(),
'voucher_no' => 'DEP-002',
'received_from' => 'Customer B',
'note' => 'Bank expense from sales',
'created_by' => 1,
],
];
foreach ($expenses as $dep) {
$fund = Fund::where('restaurant_id', $restaurantId)
->where('name', $dep['fund_name'])
->first();
$account = Account::where('restaurant_id', $restaurantId)
->where('code', $dep['account_code'])
->first();
if (! $fund || ! $account) {
continue;
}
DB::transaction(function () use ($restaurantId, $fund, $account, $dep) {
// 1⃣ Create Expense
$expense = Expense::create([
'restaurant_id' => $restaurantId,
'fund_id' => $fund->id,
'account_id' => $account->id,
'expense_category_id' => 1,
'amount' => $dep['amount'],
'transaction_date' => $dep['transaction_date'],
'voucher_no' => $dep['voucher_no'],
'received_from' => $dep['received_from'],
'note' => $dep['note'],
'created_by' => $dep['created_by'],
'status' => 1,
]);
// 2⃣ Create Transaction
$transaction = Transaction::create([
'restaurant_id' => $restaurantId,
'fund_id' => $fund->id,
'transaction_type' => 'expense',
'transaction_date' => $dep['transaction_date'],
'reference_no' => $dep['voucher_no'],
'notes' => $dep['note'],
'total_debit' => 0,
'total_credit' => $dep['amount'],
'created_by' => $dep['created_by'],
'status' => 1,
]);
// 3⃣ Transaction Details
// Credit to Fund (increase)
TransactionDetail::create([
'restaurant_id' => $restaurantId,
'transaction_id' => $transaction->id,
'account_id' => $fund->id, // fund receives money (asset)
'debit' => $dep['amount'],
'credit' => 0,
'note' => $dep['note'].' (Fund)',
'status' => 1,
]);
// Debit from Source Account
TransactionDetail::create([
'restaurant_id' => $restaurantId,
'transaction_id' => $transaction->id,
'account_id' => $account->id, // source account (income)
'debit' => 0,
'credit' => $dep['amount'],
'note' => $dep['note'].' (Source Account)',
'status' => 1,
]);
// 4⃣ Update Fund Balance
$fund->increment('current_balance', $dep['amount']);
});
}
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace Modules\Accounting\Database\Seeders;
use Illuminate\Database\Seeder;
use Modules\Accounting\Models\Fund;
class FundSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
// In SaaS onboarding, dynamic restaurant id assigned.
// For now, making example default:
$restaurantId = 1;
/*
|--------------------------------------------------------------------------
| DEFAULT FUNDS (Cash Sources)
|--------------------------------------------------------------------------
*/
$defaultFunds = [
['name' => 'Cash', 'type' => 'asset', 'code' => 'FD-001', 'is_default' => true],
['name' => 'Bank', 'type' => 'asset', 'code' => 'FD-002', 'is_default' => false],
['name' => 'Wallet', 'type' => 'asset', 'code' => 'FD-003', 'is_default' => false],
];
foreach ($defaultFunds as $fund) {
Fund::updateOrCreate(
[
'restaurant_id' => $restaurantId,
'code' => $fund['code'],
],
[
'name' => $fund['name'],
'type' => $fund['type'],
'opening_balance' => 0,
'current_balance' => 0,
'is_default' => $fund['is_default'],
'status' => 1,
]
);
}
}
}

View File

@@ -0,0 +1,11 @@
{
"name": "Accounting",
"alias": "accounting",
"description": "",
"keywords": [],
"priority": 0,
"providers": [
"Modules\\Accounting\\Providers\\AccountingServiceProvider"
],
"files": []
}

View File

@@ -0,0 +1,15 @@
{
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build"
},
"devDependencies": {
"axios": "^1.1.2",
"laravel-vite-plugin": "^0.7.5",
"sass": "^1.69.5",
"postcss": "^8.3.7",
"vite": "^4.0.0"
}
}

View File

@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Accounting Module - {{ config('app.name', 'Laravel') }}</title>
<meta name="description" content="{{ $description ?? '' }}">
<meta name="keywords" content="{{ $keywords ?? '' }}">
<meta name="author" content="{{ $author ?? '' }}">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
{{-- Vite CSS --}}
{{-- {{ module_vite('build-accounting', 'resources/assets/sass/app.scss') }} --}}
</head>
<body>
{{ $slot }}
{{-- Vite JS --}}
{{-- {{ module_vite('build-accounting', 'resources/assets/js/app.js') }} --}}
</body>
</html>

View File

@@ -0,0 +1,5 @@
<x-accounting::layouts.master>
<h1>Hello World</h1>
<p>Module: {!! config('accounting.name') !!}</p>
</x-accounting::layouts.master>

View File

@@ -0,0 +1,27 @@
<?php
use Illuminate\Support\Facades\Route;
use Modules\Accounting\Http\Controllers\API\AccountController;
use Modules\Accounting\Http\Controllers\API\DepositCategoryController;
use Modules\Accounting\Http\Controllers\API\DepositController;
use Modules\Accounting\Http\Controllers\API\ExpenseCategoryController;
use Modules\Accounting\Http\Controllers\API\ExpenseController;
use Modules\Accounting\Http\Controllers\API\FundController;
use Modules\Accounting\Http\Controllers\API\FundTransferController;
use Modules\Accounting\Http\Controllers\API\TipController;
use Modules\Accounting\Http\Controllers\API\TipDistributionController;
Route::prefix('/v1')->group(function () {
// Protected Routes (Requires Authentication)
Route::middleware(['auth:api'])->group(function () {
Route::apiResource('accounts', AccountController::class);
Route::apiResource('funds', FundController::class);
Route::apiResource('deposit-categories', DepositCategoryController::class);
Route::apiResource('deposits', DepositController::class);
Route::apiResource('expense-categories', ExpenseCategoryController::class);
Route::apiResource('expenses', ExpenseController::class);
Route::apiResource('fund-transfers', FundTransferController::class);
Route::apiResource('tips', TipController::class);
Route::apiResource('tip-distributions', TipDistributionController::class);
});
});

View File

@@ -0,0 +1,57 @@
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import { readdirSync, statSync } from 'fs';
import { join,relative,dirname } from 'path';
import { fileURLToPath } from 'url';
export default defineConfig({
build: {
outDir: '../../public/build-accounting',
emptyOutDir: true,
manifest: true,
},
plugins: [
laravel({
publicDirectory: '../../public',
buildDirectory: 'build-accounting',
input: [
__dirname + '/resources/assets/sass/app.scss',
__dirname + '/resources/assets/js/app.js'
],
refresh: true,
}),
],
});
// Scen all resources for assets file. Return array
//function getFilePaths(dir) {
// const filePaths = [];
//
// function walkDirectory(currentPath) {
// const files = readdirSync(currentPath);
// for (const file of files) {
// const filePath = join(currentPath, file);
// const stats = statSync(filePath);
// if (stats.isFile() && !file.startsWith('.')) {
// const relativePath = 'Modules/Accounting/'+relative(__dirname, filePath);
// filePaths.push(relativePath);
// } else if (stats.isDirectory()) {
// walkDirectory(filePath);
// }
// }
// }
//
// walkDirectory(dir);
// return filePaths;
//}
//const __filename = fileURLToPath(import.meta.url);
//const __dirname = dirname(__filename);
//const assetsDir = join(__dirname, 'resources/assets');
//export const paths = getFilePaths(assetsDir);
//export const paths = [
// 'Modules/Accounting/resources/assets/sass/app.scss',
// 'Modules/Accounting/resources/assets/js/app.js',
//];

View File

@@ -0,0 +1,16 @@
<?php
namespace Modules\Authentication\Interfaces;
interface PermissionInterface
{
public function index($request, int $perPage = 50);
public function getById(int $id);
public function create(array $data);
public function update(int $id, array $data);
public function delete(int $id);
}

View File

@@ -0,0 +1,16 @@
<?php
namespace Modules\Authentication\Interfaces;
interface RoleInterface
{
public function index($request, int $perPage = 50);
public function getById(int $id);
public function create(array $data);
public function update(int $id, array $data);
public function delete(int $id);
}

View File

@@ -0,0 +1,173 @@
<?php
namespace Modules\Authentication\Repositories;
use App\Abstracts\EntityRepository;
use Exception;
use Illuminate\Contracts\Pagination\Paginator;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Query\Builder;
use Modules\Authentication\Models\Feedback;
use Symfony\Component\HttpFoundation\Response;
class FeedbackRepository extends EntityRepository
{
public string $table = Feedback::TABLE_NAME;
protected array $fillableColumns = [
'user_id',
'description',
'status',
'created_at',
'updated_at',
];
protected function getQuery(): Builder
{
return parent::getQuery();
}
public function getAll(array $filterData = []): Paginator
{
$filter = $this->getFilterData($filterData);
$query = $this->getFeedbackQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
if (isset($filter['search']) && strlen($filter['search']) > 0) {
$query = $this->filterSearchQuery($query, $filter['search']);
}
return $query
->orderBy($filter['orderBy'], $filter['order'])
->paginate($filter['perPage']);
}
protected function getFilterData(array $filterData = []): array
{
$defaultArgs = [
'perPage' => 10,
'search' => '',
'orderBy' => 'id',
'order' => 'desc',
'with_deleted' => false,
];
return array_merge($defaultArgs, $filterData);
}
private function getFeedbackQuery(): Builder
{
return $this->getQuery()
->select(
'feedback.id',
'feedback.user_id',
'feedback.description',
'feedback.status',
'feedback.created_at'
);
}
protected function filterSearchQuery(Builder|EloquentBuilder $query, string $searchedText): Builder
{
$searchable = "%$searchedText%";
return $query->where('feedback.user_id', 'LIKE', $searchable)
->orWhere('feedback.description', 'LIKE', $searchable)
->orWhere('feedback.status', 'LIKE', $searchable);
}
/**
* @throws Exception
*/
public function getByColumn(string $columnName, $columnValue, array $selects = ['*']): ?object
{
$user = $this->getFeedbackQuery()
->where($columnName, $columnValue)
->first();
if (empty($user)) {
throw new Exception(
$this->getExceptionMessage(static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE),
Response::HTTP_NOT_FOUND
);
}
return $user;
}
public function getCount(array $filterData = []): int
{
$filter = $this->getFilterData($filterData);
$query = $this->getQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
return $query->count();
}
/**
* @throws Exception
*/
public function create(array $data): object
{
try {
$data = $this->prepareForDB($data);
$userId = $this->getQuery()->insertGetId($data);
$user = Feedback::find($userId);
return $user;
} catch (Exception $exception) {
throw new Exception($exception->getMessage(), Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
/**
* @throws Exception
*/
public function prepareForDB(array $data, ?object $item = null): array
{
$data = parent::prepareForDB($data, $item);
if (empty($item)) {
$data['created_at'] = now();
$data['status'] = 1;
} else {
$data['updated_at'] = now();
}
return $data;
}
/**
* @throws Exception
*/
public function update(int $id, array $data): ?object
{
try {
$user = Feedback::find($id);
$data = $this->prepareForDB($data, $user);
parent::update($id, $data);
return $this->getById($id);
} catch (Exception $exception) {
throw new Exception($exception->getMessage(), Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
protected function getExceptionMessages(): array
{
$exceptionMessages = parent::getExceptionMessages();
$userExceptionMessages = [
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'Feedback does not exist.',
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'Feedback could not be deleted.',
];
return array_merge($exceptionMessages, $userExceptionMessages);
}
}

View File

@@ -0,0 +1,207 @@
<?php
namespace Modules\Authentication\Repositories;
use App\Abstracts\EntityRepository;
use Exception;
use Illuminate\Contracts\Pagination\Paginator;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Query\Builder;
use Modules\Authentication\Models\RestaurantImageSAASSetting;
use Symfony\Component\HttpFoundation\Response;
class RestaurantImageSAASSettingRepository extends EntityRepository
{
public string $table = RestaurantImageSAASSetting::TABLE_NAME;
protected array $fillableColumns = [
'header_logo_light_theme',
'header_logo_dark_theme',
'footer_logo_light_theme',
'footer_logo_dark_theme',
'banner_image',
'status',
'created_at',
'updated_at',
'deleted_at',
];
protected function getQuery(): Builder
{
return parent::getQuery();
}
protected function getFilterData(array $filterData = []): array
{
$defaultArgs = [
'perPage' => 10,
'search' => '',
'orderBy' => 'id',
'order' => 'desc',
'with_deleted' => false,
];
return array_merge($defaultArgs, $filterData);
}
private function getRestaurantImageSAASSettingQuery(): Builder
{
return $this->getQuery()
->select(
"{$this->table}.id",
"{$this->table}.header_logo_light_theme",
"{$this->table}.header_logo_dark_theme",
"{$this->table}.footer_logo_light_theme",
"{$this->table}.footer_logo_dark_theme",
"{$this->table}.banner_image",
"{$this->table}.status",
"{$this->table}.created_at",
"{$this->table}.deleted_at"
);
}
protected function filterSearchQuery(Builder|EloquentBuilder $query, string $searchedText): Builder
{
$searchable = "%$searchedText%";
return $query->where("{$this->table}.name", 'LIKE', $searchable)
->orWhere("{$this->table}.status", 'LIKE', $searchable);
}
public function getAll(array $filterData = []): Paginator
{
$filter = $this->getFilterData($filterData);
$query = $this->getRestaurantImageSAASSettingQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
if (! empty($filter['search'])) {
$query = $this->filterSearchQuery($query, $filter['search']);
}
return $query
->orderBy($filter['orderBy'], $filter['order'])
->paginate($filter['perPage']);
}
public function getCount(array $filterData = []): int
{
$filter = $this->getFilterData($filterData);
$query = $this->getQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
return $query->count();
}
/**
* @throws Exception
*/
public function getByColumn(string $columnName, $columnValue, array $selects = ['*']): ?object
{
$item = $this->getRestaurantImageSAASSettingQuery()
->where($columnName, $columnValue)
->first($selects);
if (empty($item)) {
throw new Exception(
$this->getExceptionMessage(static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE),
Response::HTTP_NOT_FOUND
);
}
return $item;
}
/**
* @throws Exception
*/
public function create(array $data): object
{
$data = $this->prepareForDB($data);
$id = $this->getQuery()->insertGetId($data);
return RestaurantImageSAASSetting::find($id);
}
/**
* @throws Exception
*/
public function update(int $id, array $data): object
{
$item = RestaurantImageSAASSetting::findOrFail($id);
$data = $this->prepareForDB($data, $item);
parent::update($id, $data);
return $this->getById($id);
}
/**
* @throws Exception
*/
public function prepareForDB(array $data, ?object $item = null): array
{
$data = parent::prepareForDB($data, $item);
if (empty($item)) {
$data['created_at'] = now();
$data['status'] = 1;
if (! empty($data['header_logo_light_theme']) && $data['header_logo_light_theme'] instanceof \Illuminate\Http\UploadedFile) {
$data['header_logo_light_theme'] = fileUploader('restaurant_image_settings/', 'png', $data['header_logo_light_theme']);
}
if (! empty($data['header_logo_dark_theme']) && $data['header_logo_dark_theme'] instanceof \Illuminate\Http\UploadedFile) {
$data['header_logo_dark_theme'] = fileUploader('restaurant_image_settings/', 'png', $data['header_logo_dark_theme']);
}
if (! empty($data['footer_logo_light_theme']) && $data['footer_logo_light_theme'] instanceof \Illuminate\Http\UploadedFile) {
$data['footer_logo_light_theme'] = fileUploader('restaurant_image_settings/', 'png', $data['footer_logo_light_theme']);
}
if (! empty($data['footer_logo_dark_theme']) && $data['footer_logo_dark_theme'] instanceof \Illuminate\Http\UploadedFile) {
$data['footer_logo_dark_theme'] = fileUploader('restaurant_image_settings/', 'png', $data['footer_logo_dark_theme']);
}
if (! empty($data['banner_image']) && $data['banner_image'] instanceof \Illuminate\Http\UploadedFile) {
$data['banner_image'] = fileUploader('restaurant_image_settings/', 'png', $data['banner_image']);
}
} else {
if (! empty($data['header_logo_light_theme']) && $data['header_logo_light_theme'] instanceof \Illuminate\Http\UploadedFile) {
$data['header_logo_light_theme'] = fileUploader('restaurant_image_settings/', 'png', $data['header_logo_light_theme'], $item->header_logo_light_theme);
}
if (! empty($data['header_logo_dark_theme']) && $data['header_logo_dark_theme'] instanceof \Illuminate\Http\UploadedFile) {
$data['header_logo_dark_theme'] = fileUploader('restaurant_image_settings/', 'png', $data['header_logo_dark_theme'], $item->header_logo_dark_theme);
}
if (! empty($data['footer_logo_light_theme']) && $data['footer_logo_light_theme'] instanceof \Illuminate\Http\UploadedFile) {
$data['footer_logo_light_theme'] = fileUploader('restaurant_image_settings/', 'png', $data['footer_logo_light_theme'], $item->footer_logo_light_theme);
}
if (! empty($data['footer_logo_dark_theme']) && $data['footer_logo_dark_theme'] instanceof \Illuminate\Http\UploadedFile) {
$data['footer_logo_dark_theme'] = fileUploader('restaurant_image_settings/', 'png', $data['footer_logo_dark_theme'], $item->footer_logo_dark_theme);
}
if (! empty($data['banner_image']) && $data['banner_image'] instanceof \Illuminate\Http\UploadedFile) {
$data['banner_image'] = fileUploader('restaurant_image_settings/', 'png', $data['banner_image'], $item->banner_image);
}
$data['updated_at'] = now();
}
return $data;
}
protected function getExceptionMessages(): array
{
return [
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'RestaurantImageSAASSetting does not exist.',
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'RestaurantImageSAASSetting could not be deleted.',
];
}
}

View File

@@ -0,0 +1,210 @@
<?php
namespace Modules\Authentication\Repositories;
use App\Abstracts\EntityRepository;
use Exception;
use Illuminate\Contracts\Pagination\Paginator;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Query\Builder;
use Modules\Authentication\Models\RestaurantImageSetting;
use Symfony\Component\HttpFoundation\Response;
class RestaurantImageSettingRepository extends EntityRepository
{
public string $table = RestaurantImageSetting::TABLE_NAME;
protected array $fillableColumns = [
'restaurant_id',
'header_logo_light_theme',
'header_logo_dark_theme',
'footer_logo_light_theme',
'footer_logo_dark_theme',
'banner_image',
'status',
'created_at',
'updated_at',
'deleted_at',
];
protected function getQuery(): Builder
{
return parent::getQuery();
}
protected function getFilterData(array $filterData = []): array
{
$defaultArgs = [
'perPage' => 10,
'search' => '',
'orderBy' => 'id',
'order' => 'desc',
'with_deleted' => false,
];
return array_merge($defaultArgs, $filterData);
}
private function getRestaurantImageSettingQuery(): Builder
{
return $this->getQuery()
->select(
"{$this->table}.id",
"{$this->table}.restaurant_id",
"{$this->table}.header_logo_light_theme",
"{$this->table}.header_logo_dark_theme",
"{$this->table}.footer_logo_light_theme",
"{$this->table}.footer_logo_dark_theme",
"{$this->table}.banner_image",
"{$this->table}.status",
"{$this->table}.created_at",
"{$this->table}.deleted_at"
);
}
protected function filterSearchQuery(Builder|EloquentBuilder $query, string $searchedText): Builder
{
$searchable = "%$searchedText%";
return $query->where("{$this->table}.name", 'LIKE', $searchable)
->orWhere("{$this->table}.status", 'LIKE', $searchable);
}
public function getAll(array $filterData = []): Paginator
{
$filter = $this->getFilterData($filterData);
$query = $this->getRestaurantImageSettingQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
if (! empty($filter['search'])) {
$query = $this->filterSearchQuery($query, $filter['search']);
}
return $query
->orderBy($filter['orderBy'], $filter['order'])
->paginate($filter['perPage']);
}
public function getCount(array $filterData = []): int
{
$filter = $this->getFilterData($filterData);
$query = $this->getQuery();
if (! $filter['with_deleted']) {
$query->whereNull("{$this->table}.deleted_at");
}
return $query->count();
}
/**
* @throws Exception
*/
public function getByColumn(string $columnName, $columnValue, array $selects = ['*']): ?object
{
$item = $this->getRestaurantImageSettingQuery()
->where($columnName, $columnValue)
->first($selects);
if (empty($item)) {
throw new Exception(
$this->getExceptionMessage(static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE),
Response::HTTP_NOT_FOUND
);
}
return $item;
}
/**
* @throws Exception
*/
public function create(array $data): object
{
$data = $this->prepareForDB($data);
$id = $this->getQuery()->insertGetId($data);
return RestaurantImageSetting::find($id);
}
/**
* @throws Exception
*/
public function update(int $id, array $data): object
{
$item = RestaurantImageSetting::findOrFail($id);
$data = $this->prepareForDB($data, $item);
parent::update($id, $data);
return $this->getById($id);
}
/**
* @throws Exception
*/
public function prepareForDB(array $data, ?object $item = null): array
{
$data = parent::prepareForDB($data, $item);
if (empty($item)) {
$data['created_at'] = now();
$data['restaurant_id'] = $this->getCurrentRestaurantId();
$data['status'] = 1;
if (! empty($data['header_logo_light_theme']) && $data['header_logo_light_theme'] instanceof \Illuminate\Http\UploadedFile) {
$data['header_logo_light_theme'] = fileUploader('restaurant_image_settings/', 'png', $data['header_logo_light_theme']);
}
if (! empty($data['header_logo_dark_theme']) && $data['header_logo_dark_theme'] instanceof \Illuminate\Http\UploadedFile) {
$data['header_logo_dark_theme'] = fileUploader('restaurant_image_settings/', 'png', $data['header_logo_dark_theme']);
}
if (! empty($data['footer_logo_light_theme']) && $data['footer_logo_light_theme'] instanceof \Illuminate\Http\UploadedFile) {
$data['footer_logo_light_theme'] = fileUploader('restaurant_image_settings/', 'png', $data['footer_logo_light_theme']);
}
if (! empty($data['footer_logo_dark_theme']) && $data['footer_logo_dark_theme'] instanceof \Illuminate\Http\UploadedFile) {
$data['footer_logo_dark_theme'] = fileUploader('restaurant_image_settings/', 'png', $data['footer_logo_dark_theme']);
}
if (! empty($data['banner_image']) && $data['banner_image'] instanceof \Illuminate\Http\UploadedFile) {
$data['banner_image'] = fileUploader('restaurant_image_settings/', 'png', $data['banner_image']);
}
} else {
if (! empty($data['header_logo_light_theme']) && $data['header_logo_light_theme'] instanceof \Illuminate\Http\UploadedFile) {
$data['header_logo_light_theme'] = fileUploader('restaurant_image_settings/', 'png', $data['header_logo_light_theme'], $item->header_logo_light_theme);
}
if (! empty($data['header_logo_dark_theme']) && $data['header_logo_dark_theme'] instanceof \Illuminate\Http\UploadedFile) {
$data['header_logo_dark_theme'] = fileUploader('restaurant_image_settings/', 'png', $data['header_logo_dark_theme'], $item->header_logo_dark_theme);
}
if (! empty($data['footer_logo_light_theme']) && $data['footer_logo_light_theme'] instanceof \Illuminate\Http\UploadedFile) {
$data['footer_logo_light_theme'] = fileUploader('restaurant_image_settings/', 'png', $data['footer_logo_light_theme'], $item->footer_logo_light_theme);
}
if (! empty($data['footer_logo_dark_theme']) && $data['footer_logo_dark_theme'] instanceof \Illuminate\Http\UploadedFile) {
$data['footer_logo_dark_theme'] = fileUploader('restaurant_image_settings/', 'png', $data['footer_logo_dark_theme'], $item->footer_logo_dark_theme);
}
if (! empty($data['banner_image']) && $data['banner_image'] instanceof \Illuminate\Http\UploadedFile) {
$data['banner_image'] = fileUploader('restaurant_image_settings/', 'png', $data['banner_image'], $item->banner_image);
}
$data['updated_at'] = now();
}
return $data;
}
protected function getExceptionMessages(): array
{
return [
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'RestaurantImageSetting does not exist.',
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'RestaurantImageSetting could not be deleted.',
];
}
}

Some files were not shown because too many files have changed in this diff Show More