migrate to gtea from bistbucket
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\AddonFood;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class AddonFoodRepository extends EntityRepository
|
||||
{
|
||||
public string $table = AddonFood::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'food_item_id',
|
||||
'addon_id',
|
||||
'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 getAddonFoodQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.food_item_id",
|
||||
"{$this->table}.addon_id",
|
||||
"{$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}.food_item_id", 'LIKE', $searchable)
|
||||
->orWhere("{$this->table}.addon_id", 'LIKE', $searchable);
|
||||
}
|
||||
|
||||
public function getAll(array $filterData = []): Paginator
|
||||
{
|
||||
$filter = $this->getFilterData($filterData);
|
||||
$query = $this->getAddonFoodQuery();
|
||||
|
||||
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->getAddonFoodQuery()
|
||||
->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 AddonFood::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = AddonFood::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 => 'AddonFood does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'AddonFood could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\Addon;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class AddonRepository extends EntityRepository
|
||||
{
|
||||
public string $table = Addon::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'name',
|
||||
'price',
|
||||
'vat',
|
||||
'pst',
|
||||
'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 getAddonQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.name",
|
||||
"{$this->table}.price",
|
||||
"{$this->table}.vat",
|
||||
"{$this->table}.pst",
|
||||
"{$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->getAddonQuery();
|
||||
|
||||
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->getAddonQuery()
|
||||
->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 Addon::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = Addon::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 => 'Addon does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'Addon could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\CustomerAddress;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class CustomerAddressRepository extends EntityRepository
|
||||
{
|
||||
public string $table = CustomerAddress::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'user_id',
|
||||
'label',
|
||||
'address_line_1',
|
||||
'address_line_2',
|
||||
'city',
|
||||
'postal_code',
|
||||
'latitude',
|
||||
'longitude',
|
||||
'is_default',
|
||||
];
|
||||
|
||||
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 getCustomerAddressQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.user_id",
|
||||
"{$this->table}.label",
|
||||
"{$this->table}.address_line_1",
|
||||
"{$this->table}.address_line_2",
|
||||
"{$this->table}.city",
|
||||
"{$this->table}.postal_code",
|
||||
"{$this->table}.latitude",
|
||||
"{$this->table}.longitude",
|
||||
"{$this->table}.is_default",
|
||||
"{$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->getCustomerAddressQuery();
|
||||
|
||||
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->getCustomerAddressQuery()
|
||||
->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 CustomerAddress::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = CustomerAddress::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 => 'CustomerAddress does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'CustomerAddress could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\Customer;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class CustomerRepository extends EntityRepository
|
||||
{
|
||||
public string $table = Customer::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'customer_code',
|
||||
'name',
|
||||
'username',
|
||||
'email',
|
||||
'phone',
|
||||
'password',
|
||||
'otp_code',
|
||||
'role_id',
|
||||
'isVerified',
|
||||
'email_verified_at',
|
||||
'avatar',
|
||||
'address',
|
||||
'gender',
|
||||
'date_of_birth',
|
||||
'nid',
|
||||
'platform',
|
||||
'device_info',
|
||||
'last_active_time',
|
||||
'meta',
|
||||
'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 getCustomerQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.customer_code",
|
||||
"{$this->table}.name",
|
||||
"{$this->table}.username",
|
||||
"{$this->table}.email",
|
||||
"{$this->table}.phone",
|
||||
"{$this->table}.password",
|
||||
"{$this->table}.otp_code",
|
||||
"{$this->table}.role_id",
|
||||
"{$this->table}.isVerified",
|
||||
"{$this->table}.email_verified_at",
|
||||
"{$this->table}.avatar",
|
||||
"{$this->table}.address",
|
||||
"{$this->table}.gender",
|
||||
"{$this->table}.date_of_birth",
|
||||
"{$this->table}.nid",
|
||||
"{$this->table}.platform",
|
||||
"{$this->table}.device_info",
|
||||
"{$this->table}.last_active_time",
|
||||
"{$this->table}.meta",
|
||||
"{$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->getCustomerQuery();
|
||||
|
||||
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->getCustomerQuery()
|
||||
->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 Customer::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = Customer::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['avatar']) && $data['avatar'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['avatar'] = fileUploader('customers/', 'png', $data['avatar']);
|
||||
}
|
||||
} else {
|
||||
if (! empty($data['avatar']) && $data['avatar'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['avatar'] = fileUploader('customers/', 'png', $data['avatar'], $item->avatar);
|
||||
}
|
||||
|
||||
$data['updated_at'] = now();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getExceptionMessages(): array
|
||||
{
|
||||
return [
|
||||
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'Customer does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'Customer could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\DeliveryCharge;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class DeliveryChargeRepository extends EntityRepository
|
||||
{
|
||||
public string $table = DeliveryCharge::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'zone_id',
|
||||
'restaurant_id',
|
||||
'type',
|
||||
'base_charge',
|
||||
'per_km_charge',
|
||||
'min_order_amount',
|
||||
'free_delivery_above',
|
||||
'is_active',
|
||||
];
|
||||
|
||||
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 getDeliveryChargeQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.zone_id",
|
||||
"{$this->table}.type",
|
||||
"{$this->table}.base_charge",
|
||||
"{$this->table}.per_km_charge",
|
||||
"{$this->table}.min_order_amount",
|
||||
"{$this->table}.free_delivery_above",
|
||||
"{$this->table}.is_active",
|
||||
"{$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->getDeliveryChargeQuery();
|
||||
|
||||
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->getDeliveryChargeQuery()
|
||||
->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 DeliveryCharge::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = DeliveryCharge::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 => 'DeliveryCharge does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'DeliveryCharge could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\FoodCategory;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class FoodCategoryRepository extends EntityRepository
|
||||
{
|
||||
public string $table = FoodCategory::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'name',
|
||||
'image',
|
||||
'parent_id',
|
||||
'is_offer',
|
||||
'start_date',
|
||||
'end_date',
|
||||
'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 getFoodCategoryQuery(): EloquentBuilder
|
||||
{
|
||||
return FoodCategory::select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.name",
|
||||
"{$this->table}.slug",
|
||||
"{$this->table}.image",
|
||||
"{$this->table}.parent_id",
|
||||
"{$this->table}.is_offer",
|
||||
"{$this->table}.start_date",
|
||||
"{$this->table}.end_date",
|
||||
"{$this->table}.status",
|
||||
"{$this->table}.created_at",
|
||||
"{$this->table}.updated_at",
|
||||
"{$this->table}.deleted_at"
|
||||
)
|
||||
->withCount('foodItems');
|
||||
}
|
||||
|
||||
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->getFoodCategoryQuery();
|
||||
|
||||
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->getFoodCategoryQuery()
|
||||
->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 FoodCategory::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = FoodCategory::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['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('food_categories/', 'png', $data['image']);
|
||||
}
|
||||
} else {
|
||||
|
||||
if (! empty($data['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('food_categories/', 'png', $data['image'], $item->image);
|
||||
}
|
||||
$data['updated_at'] = now();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getExceptionMessages(): array
|
||||
{
|
||||
return [
|
||||
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'FoodCategory does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'FoodCategory could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,349 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\DB;
|
||||
use Modules\Restaurant\Models\FoodItem;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class FoodItemRepository extends EntityRepository
|
||||
{
|
||||
public string $table = FoodItem::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'category_id',
|
||||
'menu_category_id',
|
||||
'menu_section_id',
|
||||
'name',
|
||||
'slug',
|
||||
'description',
|
||||
'food_type',
|
||||
'points',
|
||||
'is_featured',
|
||||
'is_party',
|
||||
'is_dinner',
|
||||
'is_lunch',
|
||||
'is_popular_item',
|
||||
'is_chef_special',
|
||||
'image',
|
||||
'prep_time',
|
||||
'cooking_time',
|
||||
'vat',
|
||||
'pst',
|
||||
'ingredients_cost',
|
||||
'allergens',
|
||||
'notes',
|
||||
'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 getFoodItemQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.category_id",
|
||||
"{$this->table}.menu_category_id",
|
||||
"{$this->table}.menu_section_id",
|
||||
"{$this->table}.name",
|
||||
"{$this->table}.slug",
|
||||
"{$this->table}.description",
|
||||
"{$this->table}.food_type",
|
||||
"{$this->table}.points",
|
||||
"{$this->table}.is_featured",
|
||||
"{$this->table}.is_party",
|
||||
"{$this->table}.is_dinner",
|
||||
"{$this->table}.is_lunch",
|
||||
"{$this->table}.is_popular_item",
|
||||
"{$this->table}.is_chef_special",
|
||||
"{$this->table}.image",
|
||||
"{$this->table}.prep_time",
|
||||
"{$this->table}.cooking_time",
|
||||
"{$this->table}.vat",
|
||||
"{$this->table}.pst",
|
||||
"{$this->table}.ingredients_cost",
|
||||
"{$this->table}.allergens",
|
||||
"{$this->table}.notes",
|
||||
"{$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->getFoodItemQuery();
|
||||
|
||||
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->getFoodItemQuery()
|
||||
->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
|
||||
{
|
||||
return DB::transaction(function () use ($data) {
|
||||
$variants = $data['variants'] ?? [];
|
||||
unset($data['variants']);
|
||||
|
||||
$data = $this->prepareForDB($data);
|
||||
|
||||
/** @var FoodItem $food */
|
||||
$food = FoodItem::create($data);
|
||||
|
||||
$this->syncVariants($food, $variants);
|
||||
|
||||
return $food->load('variants');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
return DB::transaction(function () use ($id, $data) {
|
||||
|
||||
/** @var FoodItem $food */
|
||||
$food = FoodItem::findOrFail($id);
|
||||
|
||||
// Extract variants array
|
||||
$variants = $data['variants'] ?? [];
|
||||
unset($data['variants']);
|
||||
|
||||
// Update food main data
|
||||
$data = $this->prepareForDB($data, $food);
|
||||
$food->update($data);
|
||||
|
||||
// Sync only changed variants
|
||||
$this->syncVariants($food, $variants);
|
||||
|
||||
return $food->load('variants');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare data for DB insert/update
|
||||
*/
|
||||
public function prepareForDB(array $data, ?object $item = null): array
|
||||
{
|
||||
if (! empty($data['prep_time'])) {
|
||||
$data['prep_time'] = date('H:i:s', strtotime($data['prep_time']));
|
||||
}
|
||||
|
||||
if (! empty($data['cooking_time'])) {
|
||||
$data['cooking_time'] = date('H:i:s', strtotime($data['cooking_time']));
|
||||
}
|
||||
|
||||
$data = parent::prepareForDB($data, $item);
|
||||
|
||||
if (! empty($data['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('food_items/', 'png', $data['image'], $item->image ?? null);
|
||||
}
|
||||
|
||||
$data['restaurant_id'] = $this->getCurrentRestaurantId();
|
||||
$data['updated_at'] = now();
|
||||
if (empty($item)) {
|
||||
$data['created_at'] = now();
|
||||
$data['status'] = 1;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync food variants safely
|
||||
*/
|
||||
private function syncVariants(FoodItem $food, array $variants): void
|
||||
{
|
||||
$existingIds = $food->variants()->pluck('id')->toArray();
|
||||
$receivedIds = [];
|
||||
|
||||
$defaultMarked = false;
|
||||
|
||||
foreach ($variants as $variant) {
|
||||
|
||||
// Determine default
|
||||
$isDefault = ! $defaultMarked && ($variant['is_default'] ?? false);
|
||||
$defaultMarked = $defaultMarked || $isDefault;
|
||||
|
||||
// If variant has ID → update
|
||||
if (! empty($variant['id'])) {
|
||||
$receivedIds[] = $variant['id'];
|
||||
|
||||
$food->variants()
|
||||
->where('id', $variant['id'])
|
||||
->update([
|
||||
'restaurant_id' => $food->restaurant_id,
|
||||
'name' => $variant['name'],
|
||||
'sku' => $variant['sku'] ?? $this->generateSku($food, $variant['name']),
|
||||
'price' => $variant['price'],
|
||||
'offer_price' => $variant['offer_price'] ?? null,
|
||||
'discount' => $variant['discount'] ?? 0,
|
||||
'unit_id' => $variant['unit_id'] ?? 'pcs',
|
||||
'stock_tracking' => $variant['stock_tracking'] ?? true,
|
||||
'ingredients_cost' => $variant['ingredients_cost'] ?? 0,
|
||||
'profit_margin' => $variant['profit_margin'] ?? 0,
|
||||
'alert_stock_quantity' => $variant['alert_stock_quantity'] ?? null,
|
||||
'combo_type' => $variant['combo_type'] ?? 'single',
|
||||
'is_active_offer' => $variant['is_active_offer'] ?? false,
|
||||
'is_default' => $isDefault,
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// If no ID → create new variant
|
||||
$newVariant = $food->variants()->create([
|
||||
'restaurant_id' => $food->restaurant_id,
|
||||
'name' => $variant['name'],
|
||||
'sku' => $this->generateSku($food, $variant['name']),
|
||||
'price' => $variant['price'],
|
||||
'offer_price' => $variant['offer_price'] ?? null,
|
||||
'discount' => $variant['discount'] ?? 0,
|
||||
'unit_id' => $variant['unit_id'] ?? 'pcs',
|
||||
'stock_tracking' => $variant['stock_tracking'] ?? true,
|
||||
'ingredients_cost' => $variant['ingredients_cost'] ?? 0,
|
||||
'profit_margin' => $variant['profit_margin'] ?? 0,
|
||||
'alert_stock_quantity' => $variant['alert_stock_quantity'] ?? null,
|
||||
'combo_type' => $variant['combo_type'] ?? 'single',
|
||||
'is_active_offer' => $variant['is_active_offer'] ?? false,
|
||||
'is_default' => $isDefault,
|
||||
'status' => 1,
|
||||
'created_at' => now(),
|
||||
]);
|
||||
|
||||
$receivedIds[] = $newVariant->id;
|
||||
}
|
||||
|
||||
// Delete only removed variants
|
||||
$toDelete = array_diff($existingIds, $receivedIds);
|
||||
|
||||
if (! empty($toDelete)) {
|
||||
$food->variants()->whereIn('id', $toDelete)->delete();
|
||||
}
|
||||
}
|
||||
// private function syncVariants(FoodItem $food, array $variants): void
|
||||
// {
|
||||
// $defaultMarked = false;
|
||||
|
||||
// foreach ($variants as $variant) {
|
||||
// $isDefault = ! $defaultMarked && ($variant['is_default'] ?? false);
|
||||
// $defaultMarked = $defaultMarked || $isDefault;
|
||||
|
||||
// $food->variants()->create([
|
||||
// 'restaurant_id' => $food->restaurant_id,
|
||||
// 'name' => $variant['name'],
|
||||
// 'sku' => $this->generateSku($food, $variant['name']),
|
||||
// 'price' => $variant['price'],
|
||||
// 'offer_price' => $variant['offer_price'] ?? null,
|
||||
// 'discount' => $variant['discount'] ?? 0,
|
||||
// 'unit_id' => $variant['unit_id'] ?? 'pcs',
|
||||
// 'stock_tracking' => $variant['stock_tracking'] ?? true,
|
||||
// 'ingredients_cost' => $variant['ingredients_cost'] ?? 0,
|
||||
// 'profit_margin' => $variant['profit_margin'] ?? 0,
|
||||
// 'alert_stock_quantity' => $variant['alert_stock_quantity'] ?? null,
|
||||
// 'combo_type' => $variant['combo_type'] ?? 'single',
|
||||
// 'is_active_offer' => $variant['is_active_offer'] ?? false,
|
||||
// 'is_default' => $isDefault,
|
||||
// 'status' => 1,
|
||||
// 'created_at' => now(),
|
||||
// ]);
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Simple SKU generator
|
||||
*/
|
||||
private function generateSku(FoodItem $food, string $variantName): string
|
||||
{
|
||||
return strtoupper(substr($food->name, 0, 3)).'-'.strtoupper(substr($variantName, 0, 3)).'-'.rand(1000, 9999);
|
||||
}
|
||||
|
||||
protected function getExceptionMessages(): array
|
||||
{
|
||||
return [
|
||||
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'FoodItem does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'FoodItem could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\FoodVariantIngredient;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class FoodVariantIngredientRepository extends EntityRepository
|
||||
{
|
||||
public string $table = FoodVariantIngredient::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'food_variant_id',
|
||||
'ingredient_id',
|
||||
'quantity',
|
||||
'wastage_percentage',
|
||||
'unit_conversion_factor',
|
||||
'optional',
|
||||
'notes',
|
||||
'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 getFoodVariantIngredientQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.food_variant_id",
|
||||
"{$this->table}.ingredient_id",
|
||||
"{$this->table}.quantity",
|
||||
"{$this->table}.wastage_percentage",
|
||||
"{$this->table}.unit_conversion_factor",
|
||||
"{$this->table}.optional",
|
||||
"{$this->table}.notes",
|
||||
"{$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->getFoodVariantIngredientQuery();
|
||||
|
||||
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->getFoodVariantIngredientQuery()
|
||||
->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 FoodVariantIngredient::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = FoodVariantIngredient::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 => 'FoodVariantIngredient does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'FoodVariantIngredient could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\FoodVariant;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class FoodVariantRepository extends EntityRepository
|
||||
{
|
||||
public string $table = FoodVariant::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'food_item_id',
|
||||
'name',
|
||||
'sku',
|
||||
'barcode',
|
||||
'price',
|
||||
'offer_price',
|
||||
'discount',
|
||||
'unit_id',
|
||||
'image',
|
||||
'description',
|
||||
'is_default',
|
||||
'stock_tracking',
|
||||
'ingredients_cost',
|
||||
'profit_margin',
|
||||
'alert_stock_quantity',
|
||||
'combo_type',
|
||||
'is_active_offer',
|
||||
'offer_start_at',
|
||||
'offer_end_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 getFoodVariantQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.food_item_id",
|
||||
"{$this->table}.name",
|
||||
"{$this->table}.sku",
|
||||
"{$this->table}.barcode",
|
||||
"{$this->table}.price",
|
||||
"{$this->table}.offer_price",
|
||||
"{$this->table}.discount",
|
||||
"{$this->table}.unit_id",
|
||||
'units.name as unit_name', // ⬅️ ADDED
|
||||
"{$this->table}.image",
|
||||
"{$this->table}.description",
|
||||
"{$this->table}.is_default",
|
||||
"{$this->table}.stock_tracking",
|
||||
"{$this->table}.ingredients_cost",
|
||||
"{$this->table}.profit_margin",
|
||||
"{$this->table}.alert_stock_quantity",
|
||||
"{$this->table}.combo_type",
|
||||
"{$this->table}.is_active_offer",
|
||||
"{$this->table}.offer_start_at",
|
||||
"{$this->table}.offer_end_at",
|
||||
"{$this->table}.status",
|
||||
"{$this->table}.created_at",
|
||||
"{$this->table}.updated_at",
|
||||
"{$this->table}.deleted_at",
|
||||
)
|
||||
->leftJoin('units', 'units.id', '=', "{$this->table}.unit_id"); // ⬅️ JOIN ADDED
|
||||
}
|
||||
|
||||
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->getFoodVariantQuery();
|
||||
|
||||
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->getFoodVariantQuery()
|
||||
->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 FoodVariant::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = FoodVariant::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['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('food_items/', 'png', $data['image']);
|
||||
}
|
||||
} else {
|
||||
if (! empty($data['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('food_items/', 'png', $data['image'], $item->image);
|
||||
}
|
||||
$data['updated_at'] = now();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getExceptionMessages(): array
|
||||
{
|
||||
return [
|
||||
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'FoodVariant does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'FoodVariant could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\FoodWaste;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class FoodWasteRepository extends EntityRepository
|
||||
{
|
||||
public string $table = FoodWaste::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'food_item_id',
|
||||
'food_variant_id',
|
||||
'quantity',
|
||||
'unit_cost',
|
||||
'reason',
|
||||
'notes',
|
||||
'wasted_by',
|
||||
'approved_by',
|
||||
'wasted_at',
|
||||
'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 getFoodWasteQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->leftJoin('food_items', 'food_items.id', '=', 'food_wastes.food_item_id')
|
||||
->leftJoin('food_variants', 'food_variants.id', '=', 'food_wastes.food_variant_id')
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.food_item_id",
|
||||
'food_items.name as food_item_name',
|
||||
"{$this->table}.food_variant_id",
|
||||
'food_variants.name as food_variant_name',
|
||||
"{$this->table}.quantity",
|
||||
"{$this->table}.unit_cost",
|
||||
"{$this->table}.reason",
|
||||
"{$this->table}.notes",
|
||||
"{$this->table}.wasted_by",
|
||||
"{$this->table}.approved_by",
|
||||
"{$this->table}.wasted_at",
|
||||
"{$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}.food_item_id", 'LIKE', $searchable)
|
||||
->orWhere("{$this->table}.status", 'LIKE', $searchable);
|
||||
}
|
||||
|
||||
public function getAll(array $filterData = []): Paginator
|
||||
{
|
||||
$filter = $this->getFilterData($filterData);
|
||||
$query = $this->getFoodWasteQuery();
|
||||
|
||||
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->getFoodWasteQuery()
|
||||
->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 FoodWaste::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = FoodWaste::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['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('Restaurant/', 'png', $data['image']);
|
||||
}
|
||||
} else {
|
||||
if (! empty($data['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('Restaurant/', 'png', $data['image'], $item->image);
|
||||
}
|
||||
|
||||
$data['updated_at'] = now();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getExceptionMessages(): array
|
||||
{
|
||||
return [
|
||||
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'FoodWaste does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'FoodWaste could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Repositories;
|
||||
|
||||
class IngredientDamageRepository
|
||||
{
|
||||
//
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\Ingredient;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class IngredientRepository extends EntityRepository
|
||||
{
|
||||
public string $table = Ingredient::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'name',
|
||||
'unit_id',
|
||||
'stock_quantity',
|
||||
'cost_per_unit',
|
||||
'low_stock_alert',
|
||||
'supplier_id',
|
||||
'last_purchase_price',
|
||||
'last_purchase_date',
|
||||
'conversion_factor',
|
||||
'reserved_quantity',
|
||||
'wastage_quantity',
|
||||
'category',
|
||||
'notes',
|
||||
'status',
|
||||
'image',
|
||||
'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 getIngredientQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.name",
|
||||
"{$this->table}.unit_id",
|
||||
'units.name as unit_name',
|
||||
'units.short_name as unit_short_name',
|
||||
"{$this->table}.stock_quantity",
|
||||
"{$this->table}.cost_per_unit",
|
||||
"{$this->table}.low_stock_alert",
|
||||
"{$this->table}.supplier_id",
|
||||
"{$this->table}.last_purchase_price",
|
||||
"{$this->table}.last_purchase_date",
|
||||
"{$this->table}.conversion_factor",
|
||||
"{$this->table}.reserved_quantity",
|
||||
"{$this->table}.wastage_quantity",
|
||||
"{$this->table}.category",
|
||||
"{$this->table}.notes",
|
||||
"{$this->table}.image",
|
||||
"{$this->table}.status",
|
||||
"{$this->table}.created_at",
|
||||
"{$this->table}.updated_at",
|
||||
"{$this->table}.deleted_at"
|
||||
)
|
||||
->leftJoin('units', "{$this->table}.unit_id", '=', 'units.id');
|
||||
}
|
||||
|
||||
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->getIngredientQuery();
|
||||
|
||||
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->getIngredientQuery()
|
||||
->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 Ingredient::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = Ingredient::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['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('ingredients/', 'png', $data['image']);
|
||||
}
|
||||
} else {
|
||||
if (! empty($data['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('ingredients/', 'png', $data['image'], $item->image);
|
||||
}
|
||||
|
||||
$data['updated_at'] = now();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getExceptionMessages(): array
|
||||
{
|
||||
return [
|
||||
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'Ingredient does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'Ingredient could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\KitchenAssign;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class KitchenAssignRepository extends EntityRepository
|
||||
{
|
||||
public string $table = KitchenAssign::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'kitchen_id',
|
||||
'user_id',
|
||||
'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 getKitchenAssignQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
'restaurants.name as restaurant_name',
|
||||
"{$this->table}.kitchen_id",
|
||||
'kitchens.name as kitchen_name',
|
||||
"{$this->table}.user_id",
|
||||
'users.first_name as user_name',
|
||||
"{$this->table}.status",
|
||||
"{$this->table}.created_at",
|
||||
"{$this->table}.deleted_at"
|
||||
)
|
||||
->leftJoin('restaurants', 'restaurants.id', '=', "{$this->table}.restaurant_id")
|
||||
->leftJoin('kitchens', 'kitchens.id', '=', "{$this->table}.kitchen_id")
|
||||
->leftJoin('users', 'users.id', '=', "{$this->table}.user_id");
|
||||
}
|
||||
|
||||
protected function filterSearchQuery(Builder|EloquentBuilder $query, string $searchedText): Builder
|
||||
{
|
||||
$searchable = "%$searchedText%";
|
||||
|
||||
return $query->where("{$this->table}.kitchen_id", 'LIKE', $searchable)
|
||||
->orWhere("{$this->table}.user_id", 'LIKE', $searchable)
|
||||
->orWhere("{$this->table}.status", 'LIKE', $searchable);
|
||||
}
|
||||
|
||||
public function getAll(array $filterData = []): Paginator
|
||||
{
|
||||
$filter = $this->getFilterData($filterData);
|
||||
$query = $this->getKitchenAssignQuery();
|
||||
|
||||
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->getKitchenAssignQuery()
|
||||
->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 KitchenAssign::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = KitchenAssign::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['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('Restaurant/', 'png', $data['image']);
|
||||
}
|
||||
} else {
|
||||
if (! empty($data['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('Restaurant/', 'png', $data['image'], $item->image);
|
||||
}
|
||||
|
||||
$data['updated_at'] = now();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getExceptionMessages(): array
|
||||
{
|
||||
return [
|
||||
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'KitchenAssign does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'KitchenAssign could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\Kitchen;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class KitchenRepository extends EntityRepository
|
||||
{
|
||||
public string $table = Kitchen::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'name',
|
||||
'serial',
|
||||
'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 getKitchenQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.name",
|
||||
"{$this->table}.serial",
|
||||
"{$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->getKitchenQuery();
|
||||
|
||||
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->getKitchenQuery()
|
||||
->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 Kitchen::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = Kitchen::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['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('Restaurant/', 'png', $data['image']);
|
||||
}
|
||||
} else {
|
||||
if (! empty($data['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('Restaurant/', 'png', $data['image'], $item->image);
|
||||
}
|
||||
|
||||
$data['updated_at'] = now();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getExceptionMessages(): array
|
||||
{
|
||||
return [
|
||||
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'Kitchen does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'Kitchen could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\LoyaltyPoint;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class LoyaltyPointRepository extends EntityRepository
|
||||
{
|
||||
public string $table = LoyaltyPoint::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'user_id',
|
||||
'order_id',
|
||||
'food_item_id',
|
||||
'points',
|
||||
'type',
|
||||
'reason',
|
||||
'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 getLoyaltyPointQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->leftJoin('users', 'users.id', '=', "{$this->table}.user_id")
|
||||
->leftJoin('food_items', 'food_items.id', '=', "{$this->table}.food_item_id")
|
||||
->leftJoin('orders', 'orders.id', '=', "{$this->table}.order_id")
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.user_id",
|
||||
'users.first_name as user_name',
|
||||
"{$this->table}.order_id",
|
||||
'orders.order_number as order_number',
|
||||
"{$this->table}.food_item_id",
|
||||
'food_items.name as food_item_name',
|
||||
"{$this->table}.points",
|
||||
"{$this->table}.type",
|
||||
"{$this->table}.reason",
|
||||
"{$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->getLoyaltyPointQuery();
|
||||
|
||||
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->getLoyaltyPointQuery()
|
||||
->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 LoyaltyPoint::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = LoyaltyPoint::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['user_id'] = Auth::id();
|
||||
|
||||
if (! empty($data['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('Restaurant/', 'png', $data['image']);
|
||||
}
|
||||
} else {
|
||||
if (! empty($data['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('Restaurant/', 'png', $data['image'], $item->image);
|
||||
}
|
||||
|
||||
$data['updated_at'] = now();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getExceptionMessages(): array
|
||||
{
|
||||
return [
|
||||
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'LoyaltyPoint does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'LoyaltyPoint could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\LoyaltyPointSetting;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class LoyaltyPointSettingRepository extends EntityRepository
|
||||
{
|
||||
public string $table = LoyaltyPointSetting::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'name',
|
||||
'from_amount',
|
||||
'to_amount',
|
||||
'amount',
|
||||
'earn_point',
|
||||
'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 getLoyaltyPointSettingQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.name",
|
||||
"{$this->table}.from_amount",
|
||||
"{$this->table}.to_amount",
|
||||
"{$this->table}.amount",
|
||||
"{$this->table}.earn_point",
|
||||
"{$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}.amount", 'LIKE', $searchable)
|
||||
->orWhere("{$this->table}.status", 'LIKE', $searchable);
|
||||
}
|
||||
|
||||
public function getAll(array $filterData = []): Paginator
|
||||
{
|
||||
$filter = $this->getFilterData($filterData);
|
||||
$query = $this->getLoyaltyPointSettingQuery();
|
||||
|
||||
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->getLoyaltyPointSettingQuery()
|
||||
->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 LoyaltyPointSetting::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = LoyaltyPointSetting::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 => 'LoyaltyPointSetting does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'LoyaltyPointSetting could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\LoyaltyRedemption;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class LoyaltyRedemptionRepository extends EntityRepository
|
||||
{
|
||||
public string $table = LoyaltyRedemption::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'user_id',
|
||||
'food_item_id',
|
||||
'points_used',
|
||||
'price',
|
||||
'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 getLoyaltyRedemptionQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->leftJoin('users', 'users.id', '=', "{$this->table}.user_id")
|
||||
->leftJoin('food_items', 'food_items.id', '=', "{$this->table}.food_item_id")
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.user_id",
|
||||
'users.first_name as user_name',
|
||||
"{$this->table}.food_item_id",
|
||||
'food_items.name as food_item_name',
|
||||
"{$this->table}.points_used",
|
||||
"{$this->table}.price",
|
||||
"{$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->getLoyaltyRedemptionQuery();
|
||||
|
||||
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->getLoyaltyRedemptionQuery()
|
||||
->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 LoyaltyRedemption::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = LoyaltyRedemption::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['user_id'] = Auth::id();
|
||||
|
||||
if (! empty($data['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('Restaurant/', 'png', $data['image']);
|
||||
}
|
||||
} else {
|
||||
if (! empty($data['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('Restaurant/', 'png', $data['image'], $item->image);
|
||||
}
|
||||
|
||||
$data['updated_at'] = now();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getExceptionMessages(): array
|
||||
{
|
||||
return [
|
||||
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'LoyaltyRedemption does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'LoyaltyRedemption could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\MenuCategory;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class MenuCategoryRepository extends EntityRepository
|
||||
{
|
||||
public string $table = MenuCategory::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'name',
|
||||
'slug',
|
||||
'icon',
|
||||
'description',
|
||||
'priority',
|
||||
'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 getMenuCategoryQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.name",
|
||||
"{$this->table}.slug",
|
||||
"{$this->table}.icon",
|
||||
"{$this->table}.description",
|
||||
"{$this->table}.priority",
|
||||
"{$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->getMenuCategoryQuery();
|
||||
|
||||
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->getMenuCategoryQuery()
|
||||
->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 MenuCategory::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = MenuCategory::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['icon']) && $data['icon'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['icon'] = fileUploader('menu_categories/', 'png', $data['icon']);
|
||||
}
|
||||
} else {
|
||||
if (! empty($data['icon']) && $data['icon'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['icon'] = fileUploader('menu_categories/', 'png', $data['icon'], $item->icon);
|
||||
}
|
||||
|
||||
$data['updated_at'] = now();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getExceptionMessages(): array
|
||||
{
|
||||
return [
|
||||
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'MenuCategory does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'MenuCategory could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\MenuSection;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class MenuSectionRepository extends EntityRepository
|
||||
{
|
||||
public string $table = MenuSection::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'menu_category_id',
|
||||
'name',
|
||||
'slug',
|
||||
'description',
|
||||
'priority',
|
||||
'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 getMenuSectionQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.menu_category_id",
|
||||
'menu_categories.name as category_name',
|
||||
"{$this->table}.name",
|
||||
"{$this->table}.slug",
|
||||
"{$this->table}.description",
|
||||
"{$this->table}.priority",
|
||||
"{$this->table}.status",
|
||||
"{$this->table}.created_at",
|
||||
"{$this->table}.updated_at",
|
||||
"{$this->table}.deleted_at"
|
||||
)
|
||||
->leftJoin('menu_categories', 'menu_categories.id', '=', "{$this->table}.menu_category_id");
|
||||
}
|
||||
|
||||
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->getMenuSectionQuery();
|
||||
|
||||
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->getMenuSectionQuery()
|
||||
->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 MenuSection::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = MenuSection::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 => 'MenuSection does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'MenuSection could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\MenuType;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class MenuTypeRepository extends EntityRepository
|
||||
{
|
||||
public string $table = MenuType::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'name',
|
||||
'slug',
|
||||
'icon',
|
||||
'description',
|
||||
'display_order',
|
||||
'status',
|
||||
'is_default',
|
||||
'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 getMenuTypeQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.name",
|
||||
"{$this->table}.slug",
|
||||
"{$this->table}.icon",
|
||||
"{$this->table}.description",
|
||||
"{$this->table}.display_order",
|
||||
"{$this->table}.status",
|
||||
"{$this->table}.is_default",
|
||||
"{$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->getMenuTypeQuery();
|
||||
|
||||
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->getMenuTypeQuery()
|
||||
->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 MenuType::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = MenuType::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['icon']) && $data['icon'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['icon'] = fileUploader('menu_types/', 'png', $data['icon']);
|
||||
}
|
||||
} else {
|
||||
if (! empty($data['icon']) && $data['icon'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['icon'] = fileUploader('menu_types/', 'png', $data['icon'], $item->icon);
|
||||
}
|
||||
|
||||
$data['updated_at'] = now();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getExceptionMessages(): array
|
||||
{
|
||||
return [
|
||||
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'MenuType does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'MenuType could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\OrderTracking;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class OrderTrackingRepository extends EntityRepository
|
||||
{
|
||||
public string $table = OrderTracking::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'order_id',
|
||||
'delivery_boy_id',
|
||||
'status',
|
||||
'latitude',
|
||||
'longitude',
|
||||
'location_name',
|
||||
'note',
|
||||
'tracked_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 getOrderTrackingQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.order_id",
|
||||
"{$this->table}.delivery_boy_id",
|
||||
"{$this->table}.status",
|
||||
"{$this->table}.latitude",
|
||||
"{$this->table}.longitude",
|
||||
"{$this->table}.location_name",
|
||||
"{$this->table}.note",
|
||||
"{$this->table}.tracked_at",
|
||||
"{$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->getOrderTrackingQuery();
|
||||
|
||||
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->getOrderTrackingQuery()
|
||||
->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 OrderTracking::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = OrderTracking::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 => 'OrderTracking does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'OrderTracking could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\PaymentMethod;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class PaymentMethodRepository extends EntityRepository
|
||||
{
|
||||
public string $table = PaymentMethod::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'name',
|
||||
'type',
|
||||
'credentials',
|
||||
'is_default',
|
||||
'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 getPaymentMethodQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.name",
|
||||
"{$this->table}.type",
|
||||
"{$this->table}.credentials",
|
||||
"{$this->table}.is_default",
|
||||
"{$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->getPaymentMethodQuery();
|
||||
|
||||
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->getPaymentMethodQuery()
|
||||
->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 PaymentMethod::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = PaymentMethod::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 => 'PaymentMethod does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'PaymentMethod could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Repositories;
|
||||
|
||||
use Modules\Restaurant\Models\Purchase;
|
||||
|
||||
class PurchaseRepository
|
||||
{
|
||||
public function getAll($filters)
|
||||
{
|
||||
$restaurantId = getUserRestaurantId();
|
||||
|
||||
$query = Purchase::with([
|
||||
'supplier:id,name,phone',
|
||||
'creator:id,first_name',
|
||||
'items.ingredient:id,name,unit_id',
|
||||
])
|
||||
->where('restaurant_id', $restaurantId);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 🔍 Search Filters
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
if (! empty($filters['search'])) {
|
||||
$search = $filters['search'];
|
||||
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('invoice_no', 'like', "%{$search}%")
|
||||
->orWhereHas('supplier', function ($sq) use ($search) {
|
||||
$sq->where('name', 'like', "%{$search}%")
|
||||
->orWhere('phone', 'like', "%{$search}%");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 🔎 Filter: Supplier
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
if (! empty($filters['supplier_id'])) {
|
||||
$query->where('supplier_id', $filters['supplier_id']);
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 📅 Filter: Purchase Date Range
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
if (! empty($filters['start_date']) && ! empty($filters['end_date'])) {
|
||||
$query->whereBetween('purchase_date', [
|
||||
$filters['start_date'],
|
||||
$filters['end_date'],
|
||||
]);
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 🧾 Filter: Payment Status
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
if (! empty($filters['payment_status'])) {
|
||||
$query->where('payment_status', $filters['payment_status']);
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 🧰 Filter: Purchase Type
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
if (! empty($filters['purchase_type'])) {
|
||||
$query->where('purchase_type', $filters['purchase_type']);
|
||||
}
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 🔽 Sorting
|
||||
|--------------------------------------------------------------------------
|
||||
| sort_by = any column (id, invoice_no, purchase_date)
|
||||
| sort_order = asc / desc
|
||||
*/
|
||||
$sortBy = $filters['sort_by'] ?? 'id';
|
||||
$sortOrder = $filters['sort_order'] ?? 'desc';
|
||||
|
||||
$query->orderBy($sortBy, $sortOrder);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 📄 Pagination
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
$perPage = $filters['per_page'] ?? 15;
|
||||
|
||||
return $query->paginate($perPage);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\QRMenuSetting;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class QRMenuSettingRepository extends EntityRepository
|
||||
{
|
||||
public string $table = QRMenuSetting::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'name',
|
||||
'menu_title',
|
||||
'logo',
|
||||
'menu_url',
|
||||
'primary_color',
|
||||
'secondary_color',
|
||||
'bg_color',
|
||||
'template',
|
||||
'description',
|
||||
'qr_code_url',
|
||||
'wifi_name',
|
||||
'wifi_ssid',
|
||||
'wifi_password',
|
||||
'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 getQRMenuSettingQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->leftJoin('restaurants', 'restaurants.id', '=', "{$this->table}.restaurant_id")
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
'restaurants.name as restaurant_name',
|
||||
"{$this->table}.name",
|
||||
"{$this->table}.menu_title",
|
||||
"{$this->table}.logo",
|
||||
"{$this->table}.menu_url",
|
||||
"{$this->table}.primary_color",
|
||||
"{$this->table}.secondary_color",
|
||||
"{$this->table}.bg_color",
|
||||
"{$this->table}.template",
|
||||
"{$this->table}.description",
|
||||
"{$this->table}.qr_code_url",
|
||||
"{$this->table}.wifi_name",
|
||||
"{$this->table}.wifi_ssid",
|
||||
"{$this->table}.wifi_password",
|
||||
"{$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->getQRMenuSettingQuery();
|
||||
|
||||
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->getQRMenuSettingQuery()
|
||||
->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 QRMenuSetting::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = QRMenuSetting::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['logo']) && $data['logo'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['logo'] = fileUploader('qr_setting_images/', 'png', $data['logo']);
|
||||
}
|
||||
} else {
|
||||
if (! empty($data['logo']) && $data['logo'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['logo'] = fileUploader('qr_setting_images/', 'png', $data['logo'], $item->logo);
|
||||
}
|
||||
|
||||
$data['updated_at'] = now();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getExceptionMessages(): array
|
||||
{
|
||||
return [
|
||||
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'QRMenuSetting does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'QRMenuSetting could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Repositories;
|
||||
|
||||
use Exception;
|
||||
use Modules\Restaurant\Models\Reservation;
|
||||
use Modules\Restaurant\Models\ReservationUnavailable;
|
||||
|
||||
class ReservationRepository
|
||||
{
|
||||
public function getAll(array $filters = [])
|
||||
{
|
||||
$query = Reservation::with(['table', 'customer']);
|
||||
|
||||
if (! empty($filters['restaurant_id'])) {
|
||||
$query->where('restaurant_id', $filters['restaurant_id']);
|
||||
}
|
||||
|
||||
if (! empty($filters['date'])) {
|
||||
$query->whereDate('reservation_date', $filters['date']);
|
||||
}
|
||||
|
||||
if (! empty($filters['status'])) {
|
||||
$query->where('status', $filters['status']);
|
||||
}
|
||||
|
||||
if (! empty($filters['search'])) {
|
||||
$search = $filters['search'];
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('note', 'like', "%$search%");
|
||||
});
|
||||
}
|
||||
|
||||
$sortBy = $filters['sort_by'] ?? 'reservation_date';
|
||||
$sortOrder = $filters['sort_order'] ?? 'desc';
|
||||
|
||||
$query->orderBy($sortBy, $sortOrder);
|
||||
|
||||
$perPage = $filters['perPage'] ?? 10;
|
||||
|
||||
return $query->paginate($perPage);
|
||||
}
|
||||
|
||||
public function store(array $data)
|
||||
{
|
||||
$this->checkAvailability($data);
|
||||
|
||||
return Reservation::create($data);
|
||||
}
|
||||
|
||||
public function checkAvailability(array $data)
|
||||
{
|
||||
$date = $data['reservation_date'];
|
||||
$start = $data['start_time'];
|
||||
$end = $data['end_time'];
|
||||
$tableId = $data['table_id'];
|
||||
|
||||
// check unavailable tables
|
||||
$unavailable = ReservationUnavailable::where('table_id', $tableId)
|
||||
->where('date', $date)
|
||||
->where(function ($q) use ($start, $end) {
|
||||
$q->whereBetween('start_time', [$start, $end])
|
||||
->orWhereBetween('end_time', [$start, $end]);
|
||||
})
|
||||
->exists();
|
||||
|
||||
if ($unavailable) {
|
||||
throw new Exception('This table is unavailable for the selected time.');
|
||||
}
|
||||
|
||||
// check existing reservations
|
||||
$conflict = Reservation::where('table_id', $tableId)
|
||||
->where('reservation_date', $date)
|
||||
->where(function ($q) use ($start, $end) {
|
||||
$q->whereBetween('start_time', [$start, $end])
|
||||
->orWhereBetween('end_time', [$start, $end]);
|
||||
})
|
||||
->whereNotIn('status', ['cancelled'])
|
||||
->exists();
|
||||
|
||||
if ($conflict) {
|
||||
throw new Exception('This table is already booked for the selected time.');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\ReservationSetting;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class ReservationSettingRepository extends EntityRepository
|
||||
{
|
||||
public string $table = ReservationSetting::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'start_time',
|
||||
'end_time',
|
||||
'max_reservation',
|
||||
'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 getReservationSettingQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.start_time",
|
||||
"{$this->table}.end_time",
|
||||
"{$this->table}.max_reservation",
|
||||
"{$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->getReservationSettingQuery();
|
||||
|
||||
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->getReservationSettingQuery()
|
||||
->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 ReservationSetting::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = ReservationSetting::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 => 'ReservationSetting does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'ReservationSetting could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\Supplier;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class SupplierRepository extends EntityRepository
|
||||
{
|
||||
public string $table = Supplier::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'name',
|
||||
'phone',
|
||||
'company_name',
|
||||
'contact_person',
|
||||
'alternate_phone',
|
||||
'email',
|
||||
'website',
|
||||
'image',
|
||||
'address',
|
||||
'city',
|
||||
'state',
|
||||
'country',
|
||||
'postal_code',
|
||||
'tax_number',
|
||||
'bank_name',
|
||||
'bank_account_name',
|
||||
'bank_account_number',
|
||||
'ifsc_code',
|
||||
'opening_balance',
|
||||
'opening_balance_date',
|
||||
'due',
|
||||
'balance',
|
||||
'supply_type',
|
||||
'payment_terms',
|
||||
'credit_limit',
|
||||
'rating',
|
||||
'notes',
|
||||
'contract_file',
|
||||
'trade_license',
|
||||
'nid_number',
|
||||
'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 getSupplierQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.name",
|
||||
"{$this->table}.phone",
|
||||
"{$this->table}.company_name",
|
||||
"{$this->table}.contact_person",
|
||||
"{$this->table}.alternate_phone",
|
||||
"{$this->table}.email",
|
||||
"{$this->table}.website",
|
||||
"{$this->table}.image",
|
||||
"{$this->table}.address",
|
||||
"{$this->table}.city",
|
||||
"{$this->table}.state",
|
||||
"{$this->table}.country",
|
||||
"{$this->table}.postal_code",
|
||||
"{$this->table}.tax_number",
|
||||
"{$this->table}.bank_name",
|
||||
"{$this->table}.bank_account_name",
|
||||
"{$this->table}.bank_account_number",
|
||||
"{$this->table}.ifsc_code",
|
||||
"{$this->table}.opening_balance",
|
||||
"{$this->table}.opening_balance_date",
|
||||
"{$this->table}.due",
|
||||
"{$this->table}.balance",
|
||||
"{$this->table}.supply_type",
|
||||
"{$this->table}.payment_terms",
|
||||
"{$this->table}.credit_limit",
|
||||
"{$this->table}.rating",
|
||||
"{$this->table}.notes",
|
||||
"{$this->table}.contract_file",
|
||||
"{$this->table}.trade_license",
|
||||
"{$this->table}.nid_number",
|
||||
"{$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->getSupplierQuery();
|
||||
|
||||
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->getSupplierQuery()
|
||||
->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 Supplier::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = Supplier::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['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('suppliers/', 'png', $data['image']);
|
||||
}
|
||||
} else {
|
||||
if (! empty($data['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('suppliers/', 'png', $data['image'], $item->image);
|
||||
}
|
||||
|
||||
$data['updated_at'] = now();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getExceptionMessages(): array
|
||||
{
|
||||
return [
|
||||
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'Supplier does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'Supplier could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\Table;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class TableRepository extends EntityRepository
|
||||
{
|
||||
public string $table = Table::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'name',
|
||||
'serial',
|
||||
'section',
|
||||
'location',
|
||||
'table_type',
|
||||
'capacity',
|
||||
'is_bookable',
|
||||
'qr_code',
|
||||
'image',
|
||||
'position_x',
|
||||
'position_y',
|
||||
'rotation',
|
||||
'z_index',
|
||||
'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 getTableQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.name",
|
||||
"{$this->table}.serial",
|
||||
"{$this->table}.section",
|
||||
"{$this->table}.location",
|
||||
"{$this->table}.table_type",
|
||||
"{$this->table}.capacity",
|
||||
"{$this->table}.is_bookable",
|
||||
"{$this->table}.qr_code",
|
||||
"{$this->table}.image",
|
||||
"{$this->table}.position_x",
|
||||
"{$this->table}.position_y",
|
||||
"{$this->table}.rotation",
|
||||
"{$this->table}.z_index",
|
||||
"{$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->getTableQuery();
|
||||
|
||||
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->getTableQuery()
|
||||
->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 Table::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = Table::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['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('table_images/', 'png', $data['image']);
|
||||
}
|
||||
} else {
|
||||
|
||||
if (! empty($data['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('table_images/', 'png', $data['image'], $item->image);
|
||||
}
|
||||
$data['updated_at'] = now();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getExceptionMessages(): array
|
||||
{
|
||||
return [
|
||||
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'Table does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'Table could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\TaxSetting;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class TaxSettingRepository extends EntityRepository
|
||||
{
|
||||
public string $table = TaxSetting::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'name',
|
||||
'reg_no',
|
||||
'type',
|
||||
'value',
|
||||
'is_default',
|
||||
'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 getTaxSettingQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.name",
|
||||
"{$this->table}.reg_no",
|
||||
"{$this->table}.type",
|
||||
"{$this->table}.value",
|
||||
"{$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->getTaxSettingQuery();
|
||||
|
||||
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->getTaxSettingQuery()
|
||||
->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 TaxSetting::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = TaxSetting::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['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('Restaurant/', 'png', $data['image']);
|
||||
}
|
||||
} else {
|
||||
if (! empty($data['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('Restaurant/', 'png', $data['image'], $item->image);
|
||||
}
|
||||
|
||||
$data['updated_at'] = now();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getExceptionMessages(): array
|
||||
{
|
||||
return [
|
||||
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'TaxSetting does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'TaxSetting could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\Unit;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class UnitRepository extends EntityRepository
|
||||
{
|
||||
public string $table = Unit::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'restaurant_id',
|
||||
'user_id',
|
||||
'name',
|
||||
'short_name',
|
||||
'type',
|
||||
'base_unit_id',
|
||||
'operator',
|
||||
'operator_value',
|
||||
'priority',
|
||||
'version',
|
||||
'is_default',
|
||||
'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 getUnitQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.restaurant_id",
|
||||
"{$this->table}.user_id",
|
||||
"{$this->table}.name",
|
||||
"{$this->table}.short_name",
|
||||
"{$this->table}.type",
|
||||
"{$this->table}.base_unit_id",
|
||||
"{$this->table}.operator",
|
||||
"{$this->table}.operator_value",
|
||||
"{$this->table}.priority",
|
||||
"{$this->table}.version",
|
||||
"{$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}.short_name", 'LIKE', $searchable);
|
||||
}
|
||||
|
||||
public function getAll(array $filterData = []): Paginator
|
||||
{
|
||||
$filter = $this->getFilterData($filterData);
|
||||
$query = $this->getUnitQuery();
|
||||
|
||||
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->getUnitQuery()
|
||||
->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 Unit::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = Unit::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['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('Restaurant/', 'png', $data['image']);
|
||||
}
|
||||
} else {
|
||||
if (! empty($data['image']) && $data['image'] instanceof \Illuminate\Http\UploadedFile) {
|
||||
$data['image'] = fileUploader('Restaurant/', 'png', $data['image'], $item->image);
|
||||
}
|
||||
|
||||
$data['updated_at'] = now();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function getExceptionMessages(): array
|
||||
{
|
||||
return [
|
||||
static::MESSAGE_ITEM_DOES_NOT_EXIST_MESSAGE => 'Unit does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'Unit could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\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\Restaurant\Models\Zone;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class ZoneRepository extends EntityRepository
|
||||
{
|
||||
public string $table = Zone::TABLE_NAME;
|
||||
|
||||
protected array $fillableColumns = [
|
||||
'name',
|
||||
'code',
|
||||
'description',
|
||||
'coordinates',
|
||||
'is_active',
|
||||
'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 getZoneQuery(): Builder
|
||||
{
|
||||
return $this->getQuery()
|
||||
->select(
|
||||
"{$this->table}.id",
|
||||
"{$this->table}.name",
|
||||
"{$this->table}.code",
|
||||
"{$this->table}.description",
|
||||
"{$this->table}.coordinates",
|
||||
"{$this->table}.is_active",
|
||||
"{$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->getZoneQuery();
|
||||
|
||||
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->getZoneQuery()
|
||||
->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 Zone::find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(int $id, array $data): object
|
||||
{
|
||||
$item = Zone::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 => 'Zone does not exist.',
|
||||
static::MESSAGE_ITEM_COULD_NOT_BE_DELETED => 'Zone could not be deleted.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\RequestSanitizerTrait;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\Addon\AddonStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\Addon\AddonUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\AddonRepository;
|
||||
|
||||
class AddonController extends Controller
|
||||
{
|
||||
use RequestSanitizerTrait;
|
||||
|
||||
public function __construct(private AddonRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'Addon has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(AddonStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'Addon 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), 'Addon has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(AddonUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'Addon 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), 'Addon has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\RequestSanitizerTrait;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\AddonFood\AddonFoodStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\AddonFood\AddonFoodUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\AddonFoodRepository;
|
||||
|
||||
class AddonFoodController extends Controller
|
||||
{
|
||||
use RequestSanitizerTrait;
|
||||
|
||||
public function __construct(private AddonFoodRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'AddonFood has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(AddonFoodStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'AddonFood 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), 'AddonFood has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(AddonFoodUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'AddonFood 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), 'AddonFood has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\CustomerAddress\CustomerAddressStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\CustomerAddress\CustomerAddressUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\CustomerAddressRepository;
|
||||
|
||||
class CustomerAddressController extends Controller
|
||||
{
|
||||
public function __construct(private CustomerAddressRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'CustomerAddress has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(CustomerAddressStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'CustomerAddress 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), 'CustomerAddress has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(CustomerAddressUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'CustomerAddress 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), 'CustomerAddress has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\RequestSanitizerTrait;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\Customer\CustomerStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\Customer\CustomerUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\CustomerRepository;
|
||||
|
||||
class CustomerController extends Controller
|
||||
{
|
||||
use RequestSanitizerTrait;
|
||||
|
||||
public function __construct(private CustomerRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'Customer has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(CustomerStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'Customer 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), 'Customer has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(CustomerUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'Customer 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), 'Customer has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\Restaurant\Models\Customer;
|
||||
use Modules\Restaurant\Models\Ingredient;
|
||||
use Modules\Restaurant\Models\Order;
|
||||
use Modules\Restaurant\Models\OrderItem;
|
||||
use Modules\Restaurant\Models\Reservation;
|
||||
use Modules\Restaurant\Models\ReservationUnavailable;
|
||||
use Modules\Restaurant\Models\Stock;
|
||||
use Modules\Restaurant\Models\Supplier;
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$restaurantId = $request->restaurant_id ?? getUserRestaurantId();
|
||||
|
||||
// 🗓 Convert date filters properly
|
||||
$start = $request->filled('start_date') ? date('Y-m-d', strtotime($request->start_date)) : Carbon::now()->startOfMonth()->toDateString();
|
||||
$end = $request->filled('end_date') ? date('Y-m-d', strtotime($request->end_date)) : Carbon::now()->toDateString();
|
||||
|
||||
/** =====================
|
||||
* 🧾 1. Order & Sales Stats
|
||||
* ===================== */
|
||||
$orderQuery = Order::query()
|
||||
->with(['customer:id,name', 'waiter:id,first_name'])
|
||||
->when($restaurantId, fn ($q, $r) => $q->where('restaurant_id', $r))
|
||||
->whereBetween(DB::raw('DATE(order_date)'), [$start, $end]);
|
||||
|
||||
$totalOrders = (clone $orderQuery)->count();
|
||||
$totalSalesAmount = (clone $orderQuery)->sum('grand_total');
|
||||
$completedOrders = (clone $orderQuery)->where('status', 'completed')->count();
|
||||
$pendingOrders = (clone $orderQuery)->where('status', 'pending')->count();
|
||||
|
||||
/** =====================
|
||||
* 🍽️ 2. Latest Orders (5)
|
||||
* ===================== */
|
||||
$latestOrders = (clone $orderQuery)
|
||||
->latest('id')
|
||||
->take(5)
|
||||
->get([
|
||||
'id',
|
||||
'order_number',
|
||||
'grand_total',
|
||||
'status',
|
||||
'order_date',
|
||||
'customer_id',
|
||||
'waiter_id',
|
||||
])
|
||||
->map(function ($order) {
|
||||
return [
|
||||
'id' => $order->id,
|
||||
'order_number' => $order->order_number,
|
||||
'grand_total' => $order->grand_total,
|
||||
'status' => $order->status,
|
||||
'order_date' => $order->order_date,
|
||||
'customer_name' => $order->customer?->name,
|
||||
'waiter_name' => $order->waiter?->first_name,
|
||||
];
|
||||
});
|
||||
|
||||
/** =====================
|
||||
* 📦 3. Ingredients & Stock
|
||||
* ===================== */
|
||||
$totalIngredients = Ingredient::where('restaurant_id', $restaurantId)->count();
|
||||
$lowStockIngredients = Ingredient::where('restaurant_id', $restaurantId)
|
||||
->whereColumn('stock_quantity', '<=', 'low_stock_alert')
|
||||
->count();
|
||||
|
||||
$totalStockValue = Ingredient::where('restaurant_id', $restaurantId)
|
||||
->sum(DB::raw('stock_quantity * cost_per_unit'));
|
||||
|
||||
/** =====================
|
||||
* 🧍 4. Customers & Suppliers
|
||||
* ===================== */
|
||||
$totalCustomers = Customer::when($restaurantId, fn ($q, $r) => $q->where('restaurant_id', $r))->count();
|
||||
$totalSuppliers = Supplier::when($restaurantId, fn ($q, $r) => $q->where('restaurant_id', $r))->count();
|
||||
|
||||
/** =====================
|
||||
* 📅 5. Reservations
|
||||
* ===================== */
|
||||
$latestReservations = Reservation::with(['customer:id,name,phone', 'table:id,name'])
|
||||
->when($restaurantId, fn ($q, $r) => $q->where('restaurant_id', $r))
|
||||
->latest('id')
|
||||
->take(5)
|
||||
->get(['id', 'customer_id', 'table_id', 'reservation_date', 'start_time', 'status'])
|
||||
->map(function ($item) {
|
||||
return [
|
||||
'id' => $item->id,
|
||||
'customer_id' => $item->customer_id,
|
||||
'customer_name' => $item->customer?->name,
|
||||
'customer_phone' => $item->customer?->phone,
|
||||
'table_name' => $item->table?->name,
|
||||
'reservation_date' => $item->reservation_date,
|
||||
'start_time' => $item->start_time,
|
||||
'status' => $item->status,
|
||||
];
|
||||
});
|
||||
|
||||
$latestUnavailable = ReservationUnavailable::with('table:id,name')
|
||||
->when($restaurantId, fn ($q, $r) => $q->where('restaurant_id', $r))
|
||||
->latest('id')
|
||||
->take(5)
|
||||
->get(['id', 'table_id', 'date', 'start_time', 'end_time', 'reason'])
|
||||
->map(function ($item) {
|
||||
return [
|
||||
'id' => $item->id,
|
||||
'table_name' => $item->table?->name,
|
||||
'date' => $item->date,
|
||||
'start_time' => $item->start_time,
|
||||
'end_time' => $item->end_time,
|
||||
'reason' => $item->reason,
|
||||
];
|
||||
});
|
||||
|
||||
/** =====================
|
||||
* 📊 6. Stocks (movement summary)
|
||||
* ===================== */
|
||||
$stockSummary = Stock::select(
|
||||
'type',
|
||||
DB::raw('SUM(quantity) as total_qty'),
|
||||
DB::raw('SUM(total_cost) as total_cost')
|
||||
)
|
||||
->when($restaurantId, fn ($q, $r) => $q->where('restaurant_id', $r))
|
||||
->whereBetween(DB::raw('DATE(created_at)'), [$start, $end])
|
||||
->groupBy('type')
|
||||
->get()
|
||||
->keyBy('type');
|
||||
|
||||
/** =====================
|
||||
* 💹 7. Sales & Purchase Comparison
|
||||
* ===================== */
|
||||
$salesItems = OrderItem::when($restaurantId, fn ($q, $r) => $q->where('restaurant_id', $r))
|
||||
->whereBetween(DB::raw('DATE(created_at)'), [$start, $end])
|
||||
->select(DB::raw('SUM(quantity) as total_qty'), DB::raw('SUM(total) as total_sales'))
|
||||
->first();
|
||||
|
||||
/** =====================
|
||||
* 📈 8. Orders Chart Data (daily, weekly, monthly)
|
||||
* ===================== */
|
||||
// --- Daily orders (last 30 days) ---
|
||||
$dailyOrders = Order::select(
|
||||
DB::raw('DATE(order_date) as date'),
|
||||
DB::raw('COUNT(*) as total')
|
||||
)
|
||||
->when($restaurantId, fn ($q, $r) => $q->where('restaurant_id', $r))
|
||||
// ->where('status', 'completed')
|
||||
->where('order_date', '>=', now()->subDays(30))
|
||||
->groupBy(DB::raw('DATE(order_date)'))
|
||||
->orderBy('date')
|
||||
->get();
|
||||
|
||||
// --- Weekly orders (last 7 days) ---
|
||||
$weeklyOrders = Order::select(
|
||||
DB::raw('DATE(order_date) as date'),
|
||||
DB::raw('COUNT(*) as total')
|
||||
)
|
||||
->when($restaurantId, fn ($q, $r) => $q->where('restaurant_id', $r))
|
||||
// ->where('status', 'completed')
|
||||
->where('order_date', '>=', now()->subDays(7))
|
||||
->groupBy(DB::raw('DATE(order_date)'))
|
||||
->orderBy('date')
|
||||
->get();
|
||||
|
||||
// --- Monthly orders (last 12 months, always show all months) ---
|
||||
$monthlyOrdersRaw = Order::select(
|
||||
DB::raw('DATE_FORMAT(order_date, "%Y-%m") as month'),
|
||||
DB::raw('COUNT(*) as total')
|
||||
)
|
||||
->when($restaurantId, fn ($q, $r) => $q->where('restaurant_id', $r))
|
||||
->where('order_date', '>=', now()->subMonths(12))
|
||||
->groupBy(DB::raw('DATE_FORMAT(order_date, "%Y-%m")'))
|
||||
->orderBy('month')
|
||||
->pluck('total', 'month'); // → key = month (YYYY-MM), value = total count
|
||||
|
||||
// --- Build full 12-month list ---
|
||||
$months = collect(range(0, 11))
|
||||
->map(function ($i) use ($monthlyOrdersRaw) {
|
||||
$date = Carbon::now()->subMonths(11 - $i);
|
||||
$monthKey = $date->format('Y-m');
|
||||
|
||||
return [
|
||||
'month' => $date->format('F Y'), // Example: "Octobor 2025"
|
||||
'total' => $monthlyOrdersRaw[$monthKey] ?? 0,
|
||||
];
|
||||
});
|
||||
|
||||
/** =====================
|
||||
* 📈 9. Final Dashboard Response
|
||||
* ===================== */
|
||||
return $this->responseSuccess([
|
||||
'filters' => [
|
||||
'start_date' => $start,
|
||||
'end_date' => $end,
|
||||
'restaurant_id' => $restaurantId,
|
||||
],
|
||||
'stats' => [
|
||||
'orders' => [
|
||||
'total' => $totalOrders,
|
||||
'completed' => $completedOrders,
|
||||
'pending' => $pendingOrders,
|
||||
'sales_amount' => round($totalSalesAmount, 2),
|
||||
],
|
||||
'ingredients' => [
|
||||
'total' => $totalIngredients,
|
||||
'low_stock' => $lowStockIngredients,
|
||||
'stock_value' => round($totalStockValue, 2),
|
||||
],
|
||||
'customers' => $totalCustomers,
|
||||
'suppliers' => $totalSuppliers,
|
||||
],
|
||||
'stock_summary' => $stockSummary,
|
||||
'latest_orders' => $latestOrders,
|
||||
'latest_reservations' => $latestReservations,
|
||||
'latest_unavailable_tables' => $latestUnavailable,
|
||||
'sales_summary' => [
|
||||
'total_items_sold' => (int) ($salesItems->total_qty ?? 0),
|
||||
'total_sales' => round($salesItems->total_sales ?? 0, 2),
|
||||
],
|
||||
'charts' => [
|
||||
'daily_orders' => $dailyOrders,
|
||||
'weekly_orders' => $weeklyOrders,
|
||||
'monthly_orders' => $months,
|
||||
],
|
||||
], 'Dashboard data fetched successfully.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\DeliveryCharge\DeliveryChargeStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\DeliveryCharge\DeliveryChargeUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\DeliveryChargeRepository;
|
||||
|
||||
class DeliveryChargeController extends Controller
|
||||
{
|
||||
public function __construct(private DeliveryChargeRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'DeliveryCharge has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(DeliveryChargeStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'DeliveryCharge 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), 'DeliveryCharge has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(DeliveryChargeUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'DeliveryCharge 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), 'DeliveryCharge has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\Restaurant\Http\Requests\FoodAvailability\FoodAvailabilityStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\FoodAvailability\FoodAvailabilityUpdateRequest;
|
||||
use Modules\Restaurant\Models\FoodAvailability;
|
||||
|
||||
class FoodAvailabilityController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$perPage = $request->input('perPage', 15);
|
||||
$sortBy = $request->input('sortBy', 'id');
|
||||
$sortDir = $request->input('sortDir', 'desc');
|
||||
|
||||
$search = $request->input('search');
|
||||
$foodItemId = $request->input('food_item_id');
|
||||
$day = $request->input('day'); // Saturday, Sunday etc.
|
||||
$startDate = $request->input('start_date');
|
||||
$endDate = $request->input('end_date');
|
||||
|
||||
$query = FoodAvailability::query()
|
||||
->with('foodItem:id,name')
|
||||
->with('times:id,food_availability_id,open_time,close_time')
|
||||
->where('restaurant_id', getUserRestaurantId());
|
||||
|
||||
// 🔍 SEARCH Filter
|
||||
if (! empty($search)) {
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('day', 'LIKE', "%{$search}%")
|
||||
->orWhereHas('foodItem', function ($fi) use ($search) {
|
||||
$fi->where('name', 'LIKE', "%{$search}%");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 🍽 Filter by food item
|
||||
if (! empty($foodItemId)) {
|
||||
$query->where('food_item_id', $foodItemId);
|
||||
}
|
||||
|
||||
// 📅 Filter by specific day
|
||||
if (! empty($day)) {
|
||||
$query->where('day', $day);
|
||||
}
|
||||
|
||||
// 📆 Filter by date range (start_date & end_date)
|
||||
if (! empty($startDate) && ! empty($endDate)) {
|
||||
$query->whereBetween('created_at', [$startDate, $endDate]);
|
||||
}
|
||||
|
||||
// 🔽 Sorting
|
||||
$query->orderBy($sortBy, $sortDir);
|
||||
|
||||
// 📄 Pagination
|
||||
$data = $query->paginate($perPage)->appends($request->query());
|
||||
|
||||
return $this->responseSuccess($data, 'Availability list fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(FoodAvailabilityStoreRequest $request): JsonResponse
|
||||
{
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
foreach ($request->availability as $item) {
|
||||
|
||||
$availability = FoodAvailability::updateOrCreate(
|
||||
[
|
||||
'restaurant_id' => getUserRestaurantId(),
|
||||
'food_item_id' => $request->food_item_id,
|
||||
'day' => $item['day'],
|
||||
],
|
||||
[
|
||||
'is_available' => true,
|
||||
]
|
||||
);
|
||||
|
||||
// Remove old times for fresh update
|
||||
$availability->times()->delete();
|
||||
|
||||
foreach ($item['times'] as $slot) {
|
||||
$availability->times()->create([
|
||||
'open_time' => $slot['open_time'],
|
||||
'close_time' => $slot['close_time'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return $this->responseSuccess([], 'Food availability created successfully.');
|
||||
} catch (Exception $e) {
|
||||
DB::rollBack();
|
||||
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function show(int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
$data = FoodAvailability::with('times')->findOrFail($id);
|
||||
|
||||
return $this->responseSuccess($data, 'Availability fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(FoodAvailabilityUpdateRequest $request, $foodItemId): JsonResponse
|
||||
{
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$restaurantId = getUserRestaurantId();
|
||||
|
||||
foreach ($request->availability as $item) {
|
||||
|
||||
// Find existing day or create new
|
||||
$availability = FoodAvailability::firstOrCreate(
|
||||
[
|
||||
'restaurant_id' => $restaurantId,
|
||||
'food_item_id' => $foodItemId,
|
||||
'day' => $item['day'],
|
||||
],
|
||||
['is_available' => true]
|
||||
);
|
||||
|
||||
// Current time slots in DB
|
||||
$existingTimes = $availability->times()->get();
|
||||
|
||||
$newTimes = collect($item['times']);
|
||||
|
||||
// Delete removed slots
|
||||
$existingTimes->each(function ($slot) use ($newTimes) {
|
||||
if (! $newTimes->contains(fn ($t) => $t['open_time'] == $slot->open_time && $t['close_time'] == $slot->close_time)) {
|
||||
$slot->delete();
|
||||
}
|
||||
});
|
||||
|
||||
// Add or update new slots
|
||||
foreach ($item['times'] as $slot) {
|
||||
// Use food_availability_id in the condition to prevent duplicates
|
||||
$availability->times()->updateOrCreate(
|
||||
[
|
||||
'food_availability_id' => $availability->id,
|
||||
'open_time' => $slot['open_time'],
|
||||
'close_time' => $slot['close_time'],
|
||||
],
|
||||
[
|
||||
'open_time' => $slot['open_time'],
|
||||
'close_time' => $slot['close_time'],
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return $this->responseSuccess([], 'Food availability updated successfully (attach/detach).');
|
||||
} catch (Exception $e) {
|
||||
DB::rollBack();
|
||||
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
$item = FoodAvailability::findOrFail($id);
|
||||
|
||||
$item->times()->delete();
|
||||
$item->delete();
|
||||
|
||||
return $this->responseSuccess([], 'Availability deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\RequestSanitizerTrait;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\FoodCategory\FoodCategoryStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\FoodCategory\FoodCategoryUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\FoodCategoryRepository;
|
||||
|
||||
class FoodCategoryController extends Controller
|
||||
{
|
||||
use RequestSanitizerTrait;
|
||||
|
||||
public function __construct(private FoodCategoryRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'FoodCategory has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(FoodCategoryStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'FoodCategory 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), 'FoodCategory has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(FoodCategoryUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'FoodCategory 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), 'FoodCategory has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\RequestSanitizerTrait;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\Restaurant\Http\Requests\FoodItem\FoodItemStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\FoodItem\FoodItemUpdateRequest;
|
||||
use Modules\Restaurant\Models\FoodItem;
|
||||
use Modules\Restaurant\Repositories\FoodItemRepository;
|
||||
|
||||
class FoodItemController extends Controller
|
||||
{
|
||||
use RequestSanitizerTrait;
|
||||
|
||||
public function __construct(private FoodItemRepository $repo) {}
|
||||
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
// Base query with eager loading
|
||||
$query = FoodItem::with([
|
||||
'category',
|
||||
'menuCategory',
|
||||
'menuSection',
|
||||
'variants',
|
||||
'defaultVariant',
|
||||
'availabilities',
|
||||
'addons',
|
||||
]);
|
||||
|
||||
// Optional: Search by name or description
|
||||
if ($request->filled('search')) {
|
||||
$search = $request->get('search');
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('name', 'like', "%{$search}%")
|
||||
->orWhere('description', 'like', "%{$search}%");
|
||||
});
|
||||
}
|
||||
|
||||
// Optional: Filter by category
|
||||
if ($request->filled('category_id')) {
|
||||
$query->where('category_id', $request->get('category_id'));
|
||||
}
|
||||
|
||||
// Optional: Filter by restaurant
|
||||
if ($request->filled('restaurant_id')) {
|
||||
$query->where('restaurant_id', $request->get('restaurant_id'));
|
||||
}
|
||||
|
||||
// Optional: Filter by food type (e.g. veg/non-veg)
|
||||
if ($request->filled('food_type')) {
|
||||
$query->where('food_type', $request->get('food_type'));
|
||||
}
|
||||
|
||||
// Optional: Filter by is_party / is_dinner / is_lunch
|
||||
foreach (['is_party', 'is_dinner', 'is_lunch', 'is_chef_special', 'is_popular_item'] as $flag) {
|
||||
if ($request->filled($flag)) {
|
||||
$query->where($flag, $request->boolean($flag));
|
||||
}
|
||||
}
|
||||
|
||||
// Pagination: default 20 per page
|
||||
$perPage = $request->get('perPage', 20);
|
||||
|
||||
$results = $query->latest()->paginate($perPage);
|
||||
|
||||
return $this->responseSuccess($results, 'Food items fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(FoodItemStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'FoodItem 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), 'FoodItem has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(FoodItemUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'FoodItem 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), 'FoodItem has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\Restaurant\Http\Requests\FoodReview\FoodReviewStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\FoodReview\FoodReviewUpdateRequest;
|
||||
use Modules\Restaurant\Models\FoodReview;
|
||||
|
||||
class FoodReviewController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$restaurantId = getUserRestaurantId();
|
||||
|
||||
$perPage = $request->get('per_page', 10);
|
||||
|
||||
$reviews = FoodReview::with([
|
||||
'replies' => function ($q) {
|
||||
$q->where('status', 1)->latest();
|
||||
},
|
||||
])
|
||||
->where('restaurant_id', $restaurantId)
|
||||
->orderBy('is_featured', 'desc')
|
||||
->orderBy('position', 'asc')
|
||||
->latest()
|
||||
->paginate($perPage);
|
||||
|
||||
return $this->responseSuccess($reviews, 'Food reviews fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(FoodReviewStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$restaurantId = getUserRestaurantId();
|
||||
$customerId = getUserId();
|
||||
|
||||
$exists = FoodReview::where([
|
||||
'restaurant_id' => $restaurantId,
|
||||
'food_item_id' => $request->food_item_id,
|
||||
'customer_id' => $customerId,
|
||||
])->exists();
|
||||
|
||||
if ($exists) {
|
||||
return $this->responseError([], 'You have already reviewed this food.');
|
||||
}
|
||||
|
||||
$data = $request->only(['rating', 'review', 'video_url']);
|
||||
$data['restaurant_id'] = $restaurantId;
|
||||
$data['food_item_id'] = $request->food_item_id;
|
||||
$data['customer_id'] = $customerId;
|
||||
$data['status'] = 'pending';
|
||||
|
||||
/** IMAGE UPLOAD (JSON) */
|
||||
if ($request->hasFile('images')) {
|
||||
$images = [];
|
||||
foreach ($request->file('images') as $img) {
|
||||
$images[] = fileUploader('food_reviews/images/', 'png', $img);
|
||||
}
|
||||
$data['images'] = $images;
|
||||
}
|
||||
|
||||
/** VIDEO FILE */
|
||||
if ($request->hasFile('video_file')) {
|
||||
$data['video_file'] = fileUploader(
|
||||
'food_reviews/videos/',
|
||||
'mp4',
|
||||
$request->file('video_file')
|
||||
);
|
||||
}
|
||||
|
||||
$review = FoodReview::create($data);
|
||||
|
||||
return $this->responseSuccess($review, 'Review submitted successfully. Awaiting approval.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function show($id): JsonResponse
|
||||
{
|
||||
try {
|
||||
$restaurantId = getUserRestaurantId();
|
||||
|
||||
$review = FoodReview::with([
|
||||
'replies' => function ($q) {
|
||||
$q->where('status', 1)->latest();
|
||||
},
|
||||
])
|
||||
->where('restaurant_id', $restaurantId)
|
||||
->findOrFail($id);
|
||||
|
||||
return $this->responseSuccess($review, 'Food review fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(FoodReviewUpdateRequest $request, $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
$restaurantId = getUserRestaurantId();
|
||||
$customerId = getUserId();
|
||||
|
||||
$review = FoodReview::where([
|
||||
'id' => $id,
|
||||
'restaurant_id' => $restaurantId,
|
||||
'customer_id' => $customerId,
|
||||
])->firstOrFail();
|
||||
|
||||
if ($review->status === 'approved') {
|
||||
return $this->responseError([], 'Approved reviews cannot be edited.');
|
||||
}
|
||||
|
||||
$data = $request->only(['rating', 'review', 'video_url']);
|
||||
|
||||
/** IMAGE JSON UPDATE */
|
||||
$images = $review->images ?? [];
|
||||
|
||||
// Remove selected images
|
||||
if ($request->filled('remove_images')) {
|
||||
foreach ($request->remove_images as $removeImg) {
|
||||
if (in_array($removeImg, $images)) {
|
||||
fileRemover('food_reviews/images/', $removeImg);
|
||||
$images = array_values(array_diff($images, [$removeImg]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add new images
|
||||
if ($request->hasFile('images')) {
|
||||
foreach ($request->file('images') as $img) {
|
||||
$images[] = fileUploader('food_reviews/images/', 'png', $img);
|
||||
}
|
||||
}
|
||||
|
||||
$data['images'] = $images;
|
||||
|
||||
/** VIDEO FILE UPDATE */
|
||||
if ($request->hasFile('video_file')) {
|
||||
$data['video_file'] = fileUploader(
|
||||
'food_reviews/videos/',
|
||||
'mp4',
|
||||
$request->file('video_file'),
|
||||
$review->video_file
|
||||
);
|
||||
}
|
||||
|
||||
$review->update($data);
|
||||
|
||||
return $this->responseSuccess($review, 'Review updated successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function destroy($id): JsonResponse
|
||||
{
|
||||
try {
|
||||
$restaurantId = getUserRestaurantId();
|
||||
$customerId = getUserId();
|
||||
|
||||
$review = FoodReview::where([
|
||||
'id' => $id,
|
||||
'restaurant_id' => $restaurantId,
|
||||
'customer_id' => $customerId,
|
||||
])->firstOrFail();
|
||||
|
||||
if ($review->status === 'approved') {
|
||||
return $this->responseError([], 'Approved reviews cannot be deleted.');
|
||||
}
|
||||
|
||||
// Delete images
|
||||
if (! empty($review->images)) {
|
||||
foreach ($review->images as $img) {
|
||||
fileRemover('food_reviews/images/', $img);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete video
|
||||
if ($review->video_file) {
|
||||
fileRemover('food_reviews/videos/', $review->video_file);
|
||||
}
|
||||
|
||||
$review->delete();
|
||||
|
||||
return $this->responseSuccess([], 'Review deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\Restaurant\Http\Requests\FoodReviewReply\FoodReviewReplyStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\FoodReviewReply\FoodReviewReplyUpdateRequest;
|
||||
use Modules\Restaurant\Models\FoodReviewReply;
|
||||
|
||||
class FoodReviewReplyController extends Controller
|
||||
{
|
||||
/**
|
||||
* List replies for a review
|
||||
*/
|
||||
public function index(Request $request, $reviewId): JsonResponse
|
||||
{
|
||||
try {
|
||||
$perPage = $request->get('per_page', 10);
|
||||
|
||||
$replies = FoodReviewReply::where('review_id', $reviewId)
|
||||
->where('status', 1)
|
||||
->latest()
|
||||
->paginate($perPage);
|
||||
|
||||
return $this->responseSuccess($replies, 'Replies fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a reply
|
||||
*/
|
||||
public function store(FoodReviewReplyStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$restaurantId = getUserRestaurantId();
|
||||
$userId = getUserId();
|
||||
$userType = $request->user_type ?? 'customer'; // default customer
|
||||
|
||||
$data = [
|
||||
'restaurant_id' => $restaurantId,
|
||||
'review_id' => $request->review_id,
|
||||
'user_type' => $userType,
|
||||
'message' => $request->message,
|
||||
];
|
||||
|
||||
// Assign correct ID based on type
|
||||
if ($userType === 'admin') {
|
||||
$data['user_id'] = $userId;
|
||||
} else {
|
||||
$data['customer_id'] = $userId;
|
||||
}
|
||||
|
||||
/** Attachments upload */
|
||||
if ($request->hasFile('attachments')) {
|
||||
$attachments = [];
|
||||
foreach ($request->file('attachments') as $file) {
|
||||
$attachments[] = fileUploader('review_replies/attachments/', 'png', $file);
|
||||
}
|
||||
$data['attachments'] = $attachments;
|
||||
}
|
||||
|
||||
$reply = FoodReviewReply::create($data);
|
||||
|
||||
return $this->responseSuccess($reply, 'Reply created successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show single reply
|
||||
*/
|
||||
public function show($id): JsonResponse
|
||||
{
|
||||
try {
|
||||
$reply = FoodReviewReply::findOrFail($id);
|
||||
|
||||
return $this->responseSuccess($reply, 'Reply fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a reply
|
||||
*/
|
||||
public function update(FoodReviewReplyUpdateRequest $request, $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
$userId = getUserId();
|
||||
$reply = FoodReviewReply::findOrFail($id);
|
||||
|
||||
// Permission: Only the owner (admin/moderator or customer) can edit
|
||||
if (($reply->user_type === 'admin' && $reply->user_id !== $userId) ||
|
||||
($reply->user_type === 'customer' && $reply->customer_id !== $userId)
|
||||
) {
|
||||
return $this->responseError([], 'You are not authorized to edit this reply.');
|
||||
}
|
||||
|
||||
$data = $request->only(['message']);
|
||||
|
||||
$attachments = $reply->attachments ?? [];
|
||||
|
||||
// Remove selected attachments
|
||||
if ($request->filled('remove_attachments')) {
|
||||
foreach ($request->remove_attachments as $removeFile) {
|
||||
if (in_array($removeFile, $attachments)) {
|
||||
fileRemover('review_replies/attachments/', $removeFile);
|
||||
$attachments = array_values(array_diff($attachments, [$removeFile]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add new attachments
|
||||
if ($request->hasFile('attachments')) {
|
||||
foreach ($request->file('attachments') as $file) {
|
||||
$attachments[] = fileUploader('review_replies/attachments/', 'png', $file);
|
||||
}
|
||||
}
|
||||
|
||||
$data['attachments'] = $attachments;
|
||||
|
||||
$reply->update($data);
|
||||
|
||||
return $this->responseSuccess($reply, 'Reply updated successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a reply
|
||||
*/
|
||||
public function destroy($id): JsonResponse
|
||||
{
|
||||
try {
|
||||
$userId = getUserId();
|
||||
$reply = FoodReviewReply::findOrFail($id);
|
||||
|
||||
// Permission: Only owner can delete
|
||||
if (($reply->user_type === 'admin' && $reply->user_id !== $userId) ||
|
||||
($reply->user_type === 'customer' && $reply->customer_id !== $userId)
|
||||
) {
|
||||
return $this->responseError([], 'You are not authorized to delete this reply.');
|
||||
}
|
||||
|
||||
// Delete attachments
|
||||
if (! empty($reply->attachments)) {
|
||||
foreach ($reply->attachments as $file) {
|
||||
fileRemover('review_replies/attachments/', $file);
|
||||
}
|
||||
}
|
||||
|
||||
$reply->delete();
|
||||
|
||||
return $this->responseSuccess([], 'Reply deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\RequestSanitizerTrait;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\FoodVariant\FoodVariantStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\FoodVariant\FoodVariantUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\FoodVariantRepository;
|
||||
|
||||
class FoodVariantController extends Controller
|
||||
{
|
||||
use RequestSanitizerTrait;
|
||||
|
||||
public function __construct(private FoodVariantRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'FoodVariant has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(FoodVariantStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'FoodVariant 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), 'FoodVariant has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(FoodVariantUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'FoodVariant 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), 'FoodVariant has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\Authenticatable;
|
||||
use Exception;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\Restaurant\Http\Requests\FoodVariantIngredient\FoodVariantIngredientStoreRequest;
|
||||
use Modules\Restaurant\Models\FoodVariant;
|
||||
use Modules\Restaurant\Models\FoodVariantIngredient;
|
||||
|
||||
class FoodVariantIngredientController extends Controller
|
||||
{
|
||||
use Authenticatable;
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$perPage = $request->get('perPage', 10);
|
||||
|
||||
$variants = FoodVariant::with(['ingredients.ingredient'])
|
||||
->when($request->search, fn ($q) => $q->where('name', 'like', "%{$request->search}%"))
|
||||
->whereHas('ingredients') // only variants that have ingredients
|
||||
->paginate($perPage);
|
||||
|
||||
return $this->responseSuccess([
|
||||
'current_page' => $variants->currentPage(),
|
||||
'data' => $variants->map(function ($variant) {
|
||||
return [
|
||||
'variant_id' => $variant->id,
|
||||
'variant_name' => $variant->name,
|
||||
'ingredients' => $variant->ingredients->map(function ($fvIng) {
|
||||
return [
|
||||
'id' => $fvIng->ingredient->id ?? null,
|
||||
'ingredient_name' => $fvIng->ingredient->name ?? null,
|
||||
'quantity' => $fvIng->quantity,
|
||||
'wastage_percentage' => $fvIng->wastage_percentage,
|
||||
'unit_conversion_factor' => $fvIng->unit_conversion_factor,
|
||||
'optional' => $fvIng->optional,
|
||||
'notes' => $fvIng->notes,
|
||||
'status' => $fvIng->status,
|
||||
];
|
||||
}),
|
||||
];
|
||||
}),
|
||||
'first_page_url' => $variants->url(1),
|
||||
'from' => $variants->firstItem(),
|
||||
'last_page' => $variants->lastPage(),
|
||||
'last_page_url' => $variants->url($variants->lastPage()),
|
||||
'links' => $variants->linkCollection()->toArray(),
|
||||
'next_page_url' => $variants->nextPageUrl(),
|
||||
'path' => $request->url(),
|
||||
'per_page' => $variants->perPage(),
|
||||
'prev_page_url' => $variants->previousPageUrl(),
|
||||
'to' => $variants->lastItem(),
|
||||
'total' => $variants->total(),
|
||||
], 'Variant list fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(FoodVariantIngredientStoreRequest $request)
|
||||
{
|
||||
try {
|
||||
$food_variant_id = $request->food_variant_id;
|
||||
$ingredients = $request->ingredients;
|
||||
$restaurant_id = $this->getCurrentRestaurantId();
|
||||
|
||||
$created = [];
|
||||
foreach ($ingredients as $item) {
|
||||
$ingredient_id = $item['ingredient_id'];
|
||||
|
||||
// Check if this combination already exists
|
||||
$exists = FoodVariantIngredient::where([
|
||||
'restaurant_id' => $restaurant_id,
|
||||
'food_variant_id' => $food_variant_id,
|
||||
'ingredient_id' => $ingredient_id,
|
||||
])->exists();
|
||||
|
||||
if ($exists) {
|
||||
// Skip duplicate
|
||||
continue;
|
||||
}
|
||||
|
||||
// Prepare data
|
||||
$item['restaurant_id'] = $restaurant_id;
|
||||
$item['food_variant_id'] = $food_variant_id;
|
||||
|
||||
$created[] = FoodVariantIngredient::create($item);
|
||||
}
|
||||
|
||||
return $this->responseSuccess([
|
||||
'status' => true,
|
||||
'message' => 'FoodVariantIngredients created successfully (duplicates skipped).',
|
||||
'data' => $created,
|
||||
'errors' => null,
|
||||
], 'Ingredients processed successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([
|
||||
'status' => false,
|
||||
'message' => 'Failed to create.',
|
||||
'data' => null,
|
||||
'errors' => $e->getMessage(),
|
||||
], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
{
|
||||
try {
|
||||
$variant = FoodVariant::with(['ingredients.ingredient'])->findOrFail($id);
|
||||
|
||||
$data = [
|
||||
'variant_id' => $variant->id,
|
||||
'variant_name' => $variant->name,
|
||||
'ingredients' => $variant->ingredients->map(function ($fvIng) {
|
||||
return [
|
||||
'id' => $fvIng->ingredient->id ?? null,
|
||||
'ingredient_name' => $fvIng->ingredient->name ?? null,
|
||||
'quantity' => $fvIng->quantity,
|
||||
'wastage_percentage' => $fvIng->wastage_percentage,
|
||||
'unit_conversion_factor' => $fvIng->unit_conversion_factor,
|
||||
'optional' => $fvIng->optional,
|
||||
'notes' => $fvIng->notes,
|
||||
'status' => $fvIng->status,
|
||||
];
|
||||
}),
|
||||
];
|
||||
|
||||
return $this->responseSuccess($data, 'FoodVariant with ingredients fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], 'FoodVariant not found.');
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ Update
|
||||
public function update(Request $request, $food_variant_id)
|
||||
{
|
||||
try {
|
||||
$ingredients = $request->ingredients ?? [];
|
||||
|
||||
// Fetch the variant with its current ingredients
|
||||
$variant = FoodVariant::with('ingredients')->findOrFail($food_variant_id);
|
||||
|
||||
$existingIds = $variant->ingredients->pluck('ingredient_id')->toArray();
|
||||
$incomingIds = collect($ingredients)->pluck('ingredient_id')->toArray();
|
||||
|
||||
// Delete removed ingredients
|
||||
$toDelete = array_diff($existingIds, $incomingIds);
|
||||
if (! empty($toDelete)) {
|
||||
FoodVariantIngredient::where('food_variant_id', $food_variant_id)
|
||||
->whereIn('ingredient_id', $toDelete)
|
||||
->delete();
|
||||
}
|
||||
|
||||
$updatedOrCreated = [];
|
||||
// Add or update ingredients
|
||||
foreach ($ingredients as $item) {
|
||||
$item['restaurant_id'] = $this->getCurrentRestaurantId();
|
||||
$item['food_variant_id'] = $food_variant_id;
|
||||
|
||||
$fvIng = FoodVariantIngredient::updateOrCreate(
|
||||
[
|
||||
'food_variant_id' => $food_variant_id,
|
||||
'ingredient_id' => $item['ingredient_id'],
|
||||
],
|
||||
$item
|
||||
);
|
||||
|
||||
$updatedOrCreated[] = $fvIng;
|
||||
}
|
||||
|
||||
// Fetch updated variant data
|
||||
$variant = FoodVariant::with('ingredients.ingredient')->find($food_variant_id);
|
||||
|
||||
$data = [
|
||||
'variant_id' => $variant->id,
|
||||
'variant_name' => $variant->name,
|
||||
'ingredients' => $variant->ingredients->map(function ($fvIng) {
|
||||
return [
|
||||
'id' => $fvIng->ingredient->id ?? null,
|
||||
'ingredient_name' => $fvIng->ingredient->name ?? null,
|
||||
'quantity' => $fvIng->quantity,
|
||||
'wastage_percentage' => $fvIng->wastage_percentage,
|
||||
'unit_conversion_factor' => $fvIng->unit_conversion_factor,
|
||||
'optional' => $fvIng->optional,
|
||||
'notes' => $fvIng->notes,
|
||||
'status' => $fvIng->status,
|
||||
];
|
||||
}),
|
||||
];
|
||||
|
||||
return $this->responseSuccess($data, 'FoodVariant ingredients updated successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ Delete
|
||||
public function destroy(Request $request)
|
||||
{
|
||||
try {
|
||||
$food_variant_id = $request->food_variant_id;
|
||||
$ingredient_id = $request->ingredient_id ?? null;
|
||||
|
||||
if (! $food_variant_id) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Food Variant ID is required.',
|
||||
'data' => null,
|
||||
'errors' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
$query = FoodVariantIngredient::where('food_variant_id', $food_variant_id);
|
||||
|
||||
// If ingredient_id is provided, delete only that ingredient
|
||||
if ($ingredient_id) {
|
||||
$query->where('ingredient_id', $ingredient_id);
|
||||
}
|
||||
|
||||
$deleted = $query->delete();
|
||||
|
||||
if ($deleted) {
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'message' => $ingredient_id ?
|
||||
'Single ingredient removed successfully.' :
|
||||
'All ingredients of the variant removed successfully.',
|
||||
'data' => null,
|
||||
'errors' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'No matching record found.',
|
||||
'data' => null,
|
||||
'errors' => null,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Failed to delete.',
|
||||
'data' => null,
|
||||
'errors' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\FoodWaste\FoodWasteStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\FoodWaste\FoodWasteUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\FoodWasteRepository;
|
||||
|
||||
class FoodWasteController extends Controller
|
||||
{
|
||||
public function __construct(private FoodWasteRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'FoodWaste has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(FoodWasteStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'FoodWaste 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), 'FoodWaste has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(FoodWasteUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'FoodWaste 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), 'FoodWaste has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\RequestSanitizerTrait;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\Ingredient\IngredientStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\Ingredient\IngredientUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\IngredientRepository;
|
||||
|
||||
class IngredientController extends Controller
|
||||
{
|
||||
use RequestSanitizerTrait;
|
||||
|
||||
public function __construct(private IngredientRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'Ingredient has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(IngredientStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'Ingredient 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), 'Ingredient has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(IngredientUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'Ingredient 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), 'Ingredient has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Helper\IngredientDamageHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\Authenticatable;
|
||||
use App\Traits\RequestSanitizerTrait;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\Restaurant\Http\Requests\IngredientDamage\IngredientDamageStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\IngredientDamage\IngredientDamageUpdateRequest;
|
||||
use Modules\Restaurant\Models\IngredientDamage;
|
||||
use Modules\Restaurant\Repositories\IngredientDamageRepository;
|
||||
|
||||
class IngredientDamageController extends Controller
|
||||
{
|
||||
use Authenticatable, RequestSanitizerTrait;
|
||||
|
||||
public function __construct(private IngredientDamageRepository $repo) {}
|
||||
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$query = IngredientDamage::query()
|
||||
->with([
|
||||
'ingredient:id,name,unit_id',
|
||||
'reportedBy:id,first_name',
|
||||
])
|
||||
->when(
|
||||
$request->restaurant_id,
|
||||
fn ($q) => $q->where('restaurant_id', $request->restaurant_id)
|
||||
);
|
||||
|
||||
// 🔍 Search by ingredient name or reason
|
||||
if ($search = $request->input('search')) {
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('reason', 'like', "%{$search}%")
|
||||
->orWhereHas('ingredient', fn ($i) => $i->where('name', 'like', "%{$search}%"));
|
||||
});
|
||||
}
|
||||
|
||||
// 🗓️ Filter by date range
|
||||
if ($start = $request->input('start_date') and $end = $request->input('end_date')) {
|
||||
$query->whereBetween(DB::raw('DATE(created_at)'), [$start, $end]);
|
||||
}
|
||||
|
||||
// 🔁 Sorting
|
||||
$sortBy = $request->input('sort_by', 'created_at');
|
||||
$sortOrder = $request->input('sort_order', 'desc');
|
||||
$query->orderBy($sortBy, $sortOrder);
|
||||
|
||||
// 📄 Pagination
|
||||
$perPage = (int) $request->input('perPage', 15);
|
||||
$damageList = $query->paginate($perPage);
|
||||
|
||||
// 📊 Metadata (total damaged qty & value)
|
||||
$meta = [
|
||||
'total_damage_qty' => (float) $query->clone()->sum('quantity'),
|
||||
'total_damage_value' => (float) $query->clone()->sum(DB::raw('quantity * unit_cost')),
|
||||
'total_records' => $damageList->total(),
|
||||
];
|
||||
|
||||
return $this->responseSuccess([
|
||||
'data' => $damageList,
|
||||
'meta' => $meta,
|
||||
], 'IngredientDamage has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(IngredientDamageStoreRequest $request): JsonResponse
|
||||
{
|
||||
$data = $request->validated();
|
||||
try {
|
||||
$data['restaurant_id'] = $this->getCurrentRestaurantId();
|
||||
$damage = IngredientDamageHelper::createDamage($data);
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'message' => 'Ingredient damage has been recorded successfully.',
|
||||
'data' => $damage,
|
||||
]);
|
||||
} catch (\Illuminate\Database\QueryException $exception) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Database error: '.$exception->getMessage(),
|
||||
'data' => null,
|
||||
], 500);
|
||||
} catch (Exception $e) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => $e->getMessage(),
|
||||
'data' => null,
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
public function show(int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess([], 'IngredientDamage has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(IngredientDamageUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess([], 'IngredientDamage has been updated successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess([], 'IngredientDamage has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\KitchenAssign\KitchenAssignStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\KitchenAssign\KitchenAssignUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\KitchenAssignRepository;
|
||||
|
||||
class KitchenAssignController extends Controller
|
||||
{
|
||||
public function __construct(private KitchenAssignRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'KitchenAssign has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(KitchenAssignStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'KitchenAssign 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), 'KitchenAssign has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(KitchenAssignUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'KitchenAssign 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), 'KitchenAssign has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\Kitchen\KitchenStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\Kitchen\KitchenUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\KitchenRepository;
|
||||
|
||||
class KitchenController extends Controller
|
||||
{
|
||||
public function __construct(private KitchenRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'Kitchen has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(KitchenStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'Kitchen 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), 'Kitchen has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(KitchenUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'Kitchen 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), 'Kitchen has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\LoyaltyPoint\LoyaltyPointStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\LoyaltyPoint\LoyaltyPointUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\LoyaltyPointRepository;
|
||||
|
||||
class LoyaltyPointController extends Controller
|
||||
{
|
||||
public function __construct(private LoyaltyPointRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'LoyaltyPoint has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(LoyaltyPointStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'LoyaltyPoint 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), 'LoyaltyPoint has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(LoyaltyPointUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'LoyaltyPoint 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), 'LoyaltyPoint has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\LoyaltyPointSetting\LoyaltyPointSettingStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\LoyaltyPointSetting\LoyaltyPointSettingUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\LoyaltyPointSettingRepository;
|
||||
|
||||
class LoyaltyPointSettingController extends Controller
|
||||
{
|
||||
public function __construct(private LoyaltyPointSettingRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'LoyaltyPointSetting has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(LoyaltyPointSettingStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'LoyaltyPointSetting 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), 'LoyaltyPointSetting has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(LoyaltyPointSettingUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'LoyaltyPointSetting 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), 'LoyaltyPointSetting has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\LoyaltyRedemption\LoyaltyRedemptionStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\LoyaltyRedemption\LoyaltyRedemptionUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\LoyaltyRedemptionRepository;
|
||||
|
||||
class LoyaltyRedemptionController extends Controller
|
||||
{
|
||||
public function __construct(private LoyaltyRedemptionRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'LoyaltyRedemption has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(LoyaltyRedemptionStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'LoyaltyRedemption 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), 'LoyaltyRedemption has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(LoyaltyRedemptionUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'LoyaltyRedemption 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), 'LoyaltyRedemption has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\MenuCategory\MenuCategoryStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\MenuCategory\MenuCategoryUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\MenuCategoryRepository;
|
||||
|
||||
class MenuCategoryController extends Controller
|
||||
{
|
||||
public function __construct(private MenuCategoryRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'MenuCategory has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(MenuCategoryStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'MenuCategory 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), 'MenuCategory has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(MenuCategoryUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'MenuCategory 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), 'MenuCategory has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\MenuSection\MenuSectionStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\MenuSection\MenuSectionUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\MenuSectionRepository;
|
||||
|
||||
class MenuSectionController extends Controller
|
||||
{
|
||||
public function __construct(private MenuSectionRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'MenuSection has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(MenuSectionStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'MenuSection 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), 'MenuSection has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(MenuSectionUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'MenuSection 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), 'MenuSection has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\RequestSanitizerTrait;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\MenuType\MenuTypeStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\MenuType\MenuTypeUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\MenuTypeRepository;
|
||||
|
||||
class MenuTypeController extends Controller
|
||||
{
|
||||
use RequestSanitizerTrait;
|
||||
|
||||
public function __construct(private MenuTypeRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'MenuType has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(MenuTypeStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'MenuType 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), 'MenuType has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(MenuTypeUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'MenuType 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), 'MenuType has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Enum\ActionStatus;
|
||||
use App\Helper\OrderHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Mail\OrderInvoiceMail;
|
||||
use App\Services\Firebase\FirebaseService;
|
||||
use App\Traits\Authenticatable;
|
||||
use App\Traits\RequestSanitizerTrait;
|
||||
use App\Traits\Trackable;
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Modules\Authentication\Models\User;
|
||||
use Modules\Restaurant\Http\Requests\Order\OrderStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\Order\OrderUpdateRequest;
|
||||
use Modules\Restaurant\Http\Resources\OrderResource;
|
||||
use Modules\Restaurant\Models\Order;
|
||||
|
||||
class OrderController extends Controller
|
||||
{
|
||||
use Authenticatable, RequestSanitizerTrait, Trackable;
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
$query = Order::select('orders.*')
|
||||
->leftJoin('customers', 'orders.customer_id', '=', 'customers.id')
|
||||
->leftJoin('users as waiters', 'orders.waiter_id', '=', 'waiters.id')
|
||||
->with(['items.variation', 'items.food', 'customer', 'table', 'paymentMethod', 'waiter']);
|
||||
|
||||
if ($search = request('search')) {
|
||||
$query->where(function ($q) use ($search) {
|
||||
$search = strtolower($search); // ensure lowercase
|
||||
|
||||
$q->whereRaw('LOWER(orders.order_type) like ?', ["%{$search}%"])
|
||||
->orWhereRaw('LOWER(orders.status) like ?', ["%{$search}%"])
|
||||
->orWhereRaw('LOWER(orders.order_number) like ?', ["%{$search}%"])
|
||||
->orWhereRaw('LOWER(customers.name) like ?', ["%{$search}%"])
|
||||
->orWhereRaw('LOWER(customers.phone) like ?', ["%{$search}%"])
|
||||
->orWhereRaw('LOWER(waiters.first_name) like ?', ["%{$search}%"]);
|
||||
});
|
||||
}
|
||||
|
||||
if (request('from_date') && request('to_date')) {
|
||||
$query->whereBetween('orders.created_at', [
|
||||
request('from_date').' 00:00:00',
|
||||
request('to_date').' 23:59:59',
|
||||
]);
|
||||
}
|
||||
|
||||
// Paginate the query
|
||||
$orders = $query->orderBy('orders.created_at', 'desc')
|
||||
->paginate(request('perPage', 10));
|
||||
|
||||
// Convert to resource collection **with pagination meta**
|
||||
$ordersResource = OrderResource::collection($orders)->response()->getData(true);
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'message' => 'Orders have been fetched successfully.',
|
||||
'data' => $ordersResource['data'], // resource items
|
||||
'meta' => $ordersResource['meta'], // pagination info
|
||||
'links' => $ordersResource['links'], // pagination links
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(OrderStoreRequest $request, FirebaseService $firebase): JsonResponse
|
||||
{
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
$restaurantId = $this->getCurrentRestaurantId();
|
||||
$orderNumber = OrderHelper::generateOrderNumber($restaurantId);
|
||||
|
||||
// =========================
|
||||
// 🔹 Calculate Subtotal With Addons
|
||||
// =========================
|
||||
|
||||
$subtotal = 0;
|
||||
|
||||
foreach ($request->items as $item) {
|
||||
|
||||
// Base price calculation
|
||||
$baseTotal = $item['price'] * $item['quantity'];
|
||||
|
||||
// Addon calculation
|
||||
$addonTotal = 0;
|
||||
|
||||
if (! empty($item['addons'])) {
|
||||
foreach ($item['addons'] as $addon) {
|
||||
$addonTotal += $addon['price'];
|
||||
}
|
||||
|
||||
// Multiply addons by quantity
|
||||
$addonTotal = $addonTotal * $item['quantity'];
|
||||
}
|
||||
|
||||
// Add item total to subtotal
|
||||
$subtotal += ($baseTotal + $addonTotal);
|
||||
}
|
||||
|
||||
// Discount & Tax
|
||||
$discount = $request->discount ?? 0;
|
||||
$tax = $request->tax ?? 0;
|
||||
|
||||
// Grand Total
|
||||
$grandTotal = $subtotal - $discount + $tax;
|
||||
|
||||
// =========================
|
||||
// 🔹 Create Order
|
||||
// =========================
|
||||
|
||||
$order = Order::create([
|
||||
'restaurant_id' => $restaurantId,
|
||||
'order_number' => $orderNumber,
|
||||
'order_type' => $request->order_type,
|
||||
'status' => $request->status,
|
||||
'table_id' => $request->table_id,
|
||||
'waiter_id' => $request->waiter_id,
|
||||
'customer_id' => $request->customer_id,
|
||||
'payment_method_id' => $request->payment_method_id,
|
||||
'payment_status' => $request->payment_status ?? false,
|
||||
'subtotal' => $subtotal,
|
||||
'discount' => $discount,
|
||||
'tax' => $tax,
|
||||
'grand_total' => $grandTotal,
|
||||
'order_date' => Carbon::now(),
|
||||
'added_by' => auth()->id(),
|
||||
]);
|
||||
|
||||
// =========================
|
||||
// 🔹 Create Order Items
|
||||
// =========================
|
||||
foreach ($request->items as $item) {
|
||||
$addonTotal = 0;
|
||||
if (! empty($item['addons'])) {
|
||||
foreach ($item['addons'] as $addon) {
|
||||
$addonTotal += $addon['price'];
|
||||
}
|
||||
}
|
||||
$itemTotal =
|
||||
($item['price'] * $item['quantity']) +
|
||||
$addonTotal;
|
||||
|
||||
$order->items()->create([
|
||||
'restaurant_id' => $restaurantId,
|
||||
'food_item_id' => $item['food_item_id'],
|
||||
'food_variant_id' => $item['food_variant_id'] ?? null,
|
||||
'quantity' => $item['quantity'],
|
||||
'price' => $item['price'],
|
||||
'total' => $itemTotal,
|
||||
'addons' => ! empty($item['addons'])
|
||||
? json_encode($item['addons'])
|
||||
: null,
|
||||
]);
|
||||
|
||||
/*
|
||||
// 🔽 Ingredient deduction (optional)
|
||||
foreach ($item['ingredients'] ?? [] as $ingredient) {
|
||||
$ingredientModel = Ingredient::find($ingredient['id']);
|
||||
if ($ingredientModel) {
|
||||
$deductQty = $ingredient['quantity_required'] * $item['quantity'];
|
||||
$ingredientModel->decrement('available_quantity', $deductQty);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// =========================
|
||||
// 🔹 Action Log
|
||||
// =========================
|
||||
$user = auth()->user();
|
||||
$this->trackAction(ActionStatus::OrderCreate, User::class, $user->id, $order);
|
||||
|
||||
DB::commit();
|
||||
|
||||
// Push Notification
|
||||
// if ($user?->fcm_token) {
|
||||
// $result = $firebase->sendNotification(
|
||||
// $user->fcm_token,
|
||||
// 'Order Confirmed',
|
||||
// "Your order #{$order->id} has been confirmed!",
|
||||
// ['order_id' => $order->id]
|
||||
// );
|
||||
|
||||
// if ($result === true) {
|
||||
// return response()->json(['message' => 'Notification sent successfully']);
|
||||
// } else {
|
||||
// return response()->json(['message' => 'Failed to send notification', 'error' => $result], 500);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Directly send email
|
||||
// if ($order->customer?->email) {
|
||||
// try {
|
||||
// $result = shop_mailer_send($order->restaurant_id, $order->customer?->email, new OrderInvoiceMail($order));
|
||||
// if (! $result['status']) {
|
||||
// Log::warning("Order invoice email not sent for shop {$order->restaurant_id}: ".$result['message']);
|
||||
// }
|
||||
// Mail::to($order->customer?->email)->send(new OrderInvoiceMail($order));
|
||||
// } catch (Exception $ex) {
|
||||
// Log::error("Invoice email failed for order {$order->id}: ".$ex->getMessage());
|
||||
// }
|
||||
// }
|
||||
|
||||
// =========================
|
||||
// 🔹 Load Response Data
|
||||
// =========================
|
||||
$ordersResource = new OrderResource($order);
|
||||
|
||||
return $this->responseSuccess($ordersResource, 'Order created successfully.');
|
||||
} catch (Exception $e) {
|
||||
|
||||
DB::rollBack();
|
||||
|
||||
return $this->responseError([], 'Order creation failed: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function show(int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
$order = Order::with([
|
||||
'items.food',
|
||||
'items.variation', // add this relation
|
||||
'customer',
|
||||
'table',
|
||||
'paymentMethod',
|
||||
])->findOrFail($id);
|
||||
|
||||
return $this->responseSuccess($order, 'Order has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(OrderUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
$order = Order::with('items')->findOrFail($id);
|
||||
|
||||
// Recalculate total
|
||||
$totalAmount = collect($request->items)->sum(function ($item) {
|
||||
return $item['quantity'] * $item['price'];
|
||||
});
|
||||
|
||||
// Update order (order_number stays untouched)
|
||||
$order->update([
|
||||
'order_type' => $request->order_type,
|
||||
'status' => $request->status,
|
||||
'table_id' => $request->table_id,
|
||||
'payment_method_id' => $request->payment_method_id,
|
||||
'payment_status' => $request->payment_status ?? false,
|
||||
'waiter_id' => $request->waiter_id,
|
||||
'customer_id' => $request->customer_id,
|
||||
'grand_total' => $totalAmount,
|
||||
'updated_by' => Carbon::now(),
|
||||
]);
|
||||
|
||||
$existingItemIds = $order->items->pluck('id')->toArray();
|
||||
$requestItemIds = collect($request->items)->pluck('id')->filter()->toArray();
|
||||
|
||||
// 1️⃣ Remove items that are not in request anymore
|
||||
$itemsToDelete = array_diff($existingItemIds, $requestItemIds);
|
||||
if (! empty($itemsToDelete)) {
|
||||
$order->items()->whereIn('id', $itemsToDelete)->delete();
|
||||
}
|
||||
|
||||
// 2️⃣ Add or update items
|
||||
foreach ($request->items as $item) {
|
||||
if (isset($item['id']) && in_array($item['id'], $existingItemIds)) {
|
||||
// Update existing item
|
||||
$order->items()->where('id', $item['id'])->update([
|
||||
'restaurant_id' => $order->restaurant_id,
|
||||
'food_item_id' => $item['food_item_id'],
|
||||
'food_variant_id' => $item['food_variant_id'] ?? null,
|
||||
'quantity' => $item['quantity'],
|
||||
'price' => $item['price'],
|
||||
'total' => $item['quantity'] * $item['price'],
|
||||
]);
|
||||
} else {
|
||||
// Add new item
|
||||
$order->items()->create([
|
||||
'restaurant_id' => $order->restaurant_id,
|
||||
'food_item_id' => $item['food_item_id'],
|
||||
'food_variant_id' => $item['food_variant_id'] ?? null,
|
||||
'quantity' => $item['quantity'],
|
||||
'price' => $item['price'],
|
||||
'total' => $item['quantity'] * $item['price'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return $this->responseSuccess($order->load('items'), 'Order has been updated successfully.');
|
||||
} catch (\Throwable $e) {
|
||||
DB::rollBack();
|
||||
|
||||
return $this->responseError([], 'Failed to update order: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
$order = Order::with('items')->findOrFail($id);
|
||||
|
||||
// Delete related order items
|
||||
foreach ($order->items as $item) {
|
||||
$item->delete();
|
||||
}
|
||||
|
||||
// Delete the order
|
||||
$order->delete();
|
||||
|
||||
DB::commit();
|
||||
|
||||
return $this->responseSuccess([], 'Order and related items have been deleted successfully.');
|
||||
} catch (\Throwable $e) {
|
||||
DB::rollBack();
|
||||
|
||||
return $this->responseError([], 'Failed to delete order: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\OrderTracking\OrderTrackingStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\OrderTracking\OrderTrackingUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\OrderTrackingRepository;
|
||||
|
||||
class OrderTrackingController extends Controller
|
||||
{
|
||||
public function __construct(private OrderTrackingRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'OrderTracking has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(OrderTrackingStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'OrderTracking 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), 'OrderTracking has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(OrderTrackingUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'OrderTracking 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), 'OrderTracking has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\RequestSanitizerTrait;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\PaymentMethod\PaymentMethodStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\PaymentMethod\PaymentMethodUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\PaymentMethodRepository;
|
||||
|
||||
class PaymentMethodController extends Controller
|
||||
{
|
||||
use RequestSanitizerTrait;
|
||||
|
||||
public function __construct(private PaymentMethodRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'PaymentMethod has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(PaymentMethodStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'PaymentMethod 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), 'PaymentMethod has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(PaymentMethodUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'PaymentMethod 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), 'PaymentMethod has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Helper\PurchaseHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\Authenticatable;
|
||||
use App\Traits\RequestSanitizerTrait;
|
||||
use App\Traits\Trackable;
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\Restaurant\Http\Requests\Purchase\PurchaseStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\Purchase\PurchaseUpdateRequest;
|
||||
use Modules\Restaurant\Models\Purchase;
|
||||
use Modules\Restaurant\Models\PurchaseItem;
|
||||
use Modules\Restaurant\Models\Stock;
|
||||
use Modules\Restaurant\Repositories\PurchaseRepository;
|
||||
|
||||
class PurchaseController extends Controller
|
||||
{
|
||||
use Authenticatable, RequestSanitizerTrait, Trackable;
|
||||
|
||||
public function __construct(private PurchaseRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
$filters = request()->all();
|
||||
$data = $this->repo->getAll($filters);
|
||||
|
||||
return $this->responseSuccess($data, 'Purchase list fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(PurchaseStoreRequest $request): JsonResponse
|
||||
{
|
||||
$data = $request->validated();
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
// 1️⃣ Create Purchase
|
||||
$restaurantId = $this->getCurrentRestaurantId();
|
||||
$invoiceNo = PurchaseHelper::generateInvoiceNumber($restaurantId);
|
||||
$purchase = Purchase::create([
|
||||
'restaurant_id' => $restaurantId,
|
||||
'supplier_id' => $data['supplier_id'] ?? null,
|
||||
'invoice_no' => $invoiceNo,
|
||||
'purchase_date' => $data['purchase_date'] ?? Carbon::now(),
|
||||
'sub_total' => $data['sub_total'],
|
||||
'discount_amount' => $data['discount_amount'] ?? 0,
|
||||
'tax_amount' => $data['tax_amount'] ?? 0,
|
||||
'total_amount' => $data['total_amount'],
|
||||
'payment_status' => $data['payment_status'] ?? 'unpaid',
|
||||
'payment_method' => $data['payment_method'] ?? null,
|
||||
'purchase_type' => $data['purchase_type'] ?? 'ingredient',
|
||||
'created_by' => $data['created_by'] ?? null,
|
||||
'notes' => $data['notes'] ?? null,
|
||||
]);
|
||||
|
||||
// 2️⃣ Loop through items and create Purchase Items + Stock
|
||||
foreach ($data['items'] as $item) {
|
||||
$purchaseItem = PurchaseItem::create([
|
||||
'restaurant_id' => $restaurantId,
|
||||
'purchase_id' => $purchase->id,
|
||||
'ingredient_id' => $item['ingredient_id'],
|
||||
'food_variant_id' => $item['food_variant_id'] ?? null,
|
||||
'quantity' => $item['quantity'],
|
||||
'unit_price' => $item['unit_price'],
|
||||
'total_cost' => $item['total_cost'],
|
||||
'tax_amount' => $item['tax_amount'] ?? 0,
|
||||
'discount_amount' => $item['discount_amount'] ?? 0,
|
||||
'batch_no' => $item['batch_no'] ?? null,
|
||||
'expiry_date' => $item['expiry_date'] ?? null,
|
||||
'received_quantity' => $item['received_quantity'] ?? $item['quantity'],
|
||||
'wastage_quantity' => $item['wastage_quantity'] ?? 0,
|
||||
]);
|
||||
|
||||
// 3️⃣ Update Stock
|
||||
Stock::create([
|
||||
'restaurant_id' => $restaurantId,
|
||||
'ingredient_id' => $item['ingredient_id'],
|
||||
'type' => 'purchase',
|
||||
'quantity' => $item['received_quantity'] ?? $item['quantity'],
|
||||
'unit_cost' => $item['unit_price'],
|
||||
'total_cost' => $item['total_cost'],
|
||||
'reference_type' => 'PurchaseItem',
|
||||
'purchase_id' => $purchaseItem->id,
|
||||
'batch_no' => $item['batch_no'] ?? null,
|
||||
'expiry_date' => $item['expiry_date'] ?? null,
|
||||
'added_by' => $data['created_by'] ?? null,
|
||||
'remarks' => 'Initial purchase stock',
|
||||
]);
|
||||
}
|
||||
DB::commit();
|
||||
|
||||
return $this->responseSuccess($purchase->load('items'), 'Purchase has been created successfully.');
|
||||
} catch (Exception $e) {
|
||||
DB::rollBack();
|
||||
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function show(int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
$restaurantId = getUserRestaurantId();
|
||||
|
||||
$purchase = Purchase::with([
|
||||
'supplier:id,name,phone',
|
||||
'creator:id,first_name,last_name',
|
||||
'items' => function ($q) {
|
||||
$q->with([
|
||||
'ingredient:id,name,unit_id',
|
||||
'ingredient.unit:id,name',
|
||||
]);
|
||||
},
|
||||
])
|
||||
->where('restaurant_id', $restaurantId)
|
||||
->where('id', $id)
|
||||
->first();
|
||||
|
||||
if (! $purchase) {
|
||||
return $this->responseError([], 'Purchase not found.', 404);
|
||||
}
|
||||
|
||||
return $this->responseSuccess($purchase, 'Purchase fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(PurchaseUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
$data = $request->validated();
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$restaurantId = $this->getCurrentRestaurantId();
|
||||
|
||||
// 1️⃣ Fetch Purchase
|
||||
$purchase = Purchase::with('items')->findOrFail($id);
|
||||
|
||||
// 2️⃣ Update Purchase fields
|
||||
$purchase->update([
|
||||
'supplier_id' => $data['supplier_id'] ?? null,
|
||||
'purchase_date' => $data['purchase_date'] ?? $purchase->purchase_date,
|
||||
'sub_total' => $data['sub_total'],
|
||||
'discount_amount' => $data['discount_amount'] ?? 0,
|
||||
'tax_amount' => $data['tax_amount'] ?? 0,
|
||||
'total_amount' => $data['total_amount'],
|
||||
'payment_status' => $data['payment_status'] ?? $purchase->payment_status,
|
||||
'payment_method' => $data['payment_method'] ?? $purchase->payment_method,
|
||||
'purchase_type' => $data['purchase_type'] ?? $purchase->purchase_type,
|
||||
'created_by' => $data['created_by'] ?? $purchase->created_by,
|
||||
'notes' => $data['notes'] ?? null,
|
||||
]);
|
||||
|
||||
// Collect item IDs included in request
|
||||
$incomingItemIds = collect($data['items'])
|
||||
->pluck('id')
|
||||
->filter()
|
||||
->toArray();
|
||||
|
||||
// 3️⃣ Remove items that are NOT in request
|
||||
$itemsToDelete = $purchase->items()
|
||||
->whereNotIn('id', $incomingItemIds)
|
||||
->get();
|
||||
|
||||
foreach ($itemsToDelete as $oldItem) {
|
||||
// Delete stock related to this item
|
||||
Stock::where('reference_type', 'PurchaseItem')
|
||||
->where('purchase_id', $oldItem->id)
|
||||
->delete();
|
||||
|
||||
// Delete purchase item
|
||||
$oldItem->delete();
|
||||
}
|
||||
|
||||
// 4️⃣ Update or Create items
|
||||
foreach ($data['items'] as $item) {
|
||||
// If item has ID → update
|
||||
if (! empty($item['id'])) {
|
||||
$purchaseItem = PurchaseItem::find($item['id']);
|
||||
$purchaseItem->update([
|
||||
'ingredient_id' => $item['ingredient_id'],
|
||||
'food_variant_id' => $item['food_variant_id'] ?? null,
|
||||
'quantity' => $item['quantity'],
|
||||
'unit_price' => $item['unit_price'],
|
||||
'total_cost' => $item['total_cost'],
|
||||
'tax_amount' => $item['tax_amount'] ?? 0,
|
||||
'discount_amount' => $item['discount_amount'] ?? 0,
|
||||
'batch_no' => $item['batch_no'] ?? null,
|
||||
'expiry_date' => $item['expiry_date'] ?? null,
|
||||
'received_quantity' => $item['received_quantity'] ?? $item['quantity'],
|
||||
'wastage_quantity' => $item['wastage_quantity'] ?? 0,
|
||||
]);
|
||||
|
||||
// Update stock row
|
||||
Stock::where('reference_type', 'PurchaseItem')
|
||||
->where('purchase_id', $purchaseItem->id)
|
||||
->update([
|
||||
'ingredient_id' => $item['ingredient_id'],
|
||||
'quantity' => $item['received_quantity'] ?? $item['quantity'],
|
||||
'unit_cost' => $item['unit_price'],
|
||||
'total_cost' => $item['total_cost'],
|
||||
'batch_no' => $item['batch_no'] ?? null,
|
||||
'expiry_date' => $item['expiry_date'] ?? null,
|
||||
'added_by' => $data['created_by'] ?? $purchase->created_by,
|
||||
'remarks' => 'Updated purchase stock',
|
||||
]);
|
||||
} else {
|
||||
// No ID → Create new item
|
||||
$purchaseItem = PurchaseItem::create([
|
||||
'restaurant_id' => $restaurantId,
|
||||
'purchase_id' => $purchase->id,
|
||||
'ingredient_id' => $item['ingredient_id'],
|
||||
'food_variant_id' => $item['food_variant_id'] ?? null,
|
||||
'quantity' => $item['quantity'],
|
||||
'unit_price' => $item['unit_price'],
|
||||
'total_cost' => $item['total_cost'],
|
||||
'tax_amount' => $item['tax_amount'] ?? 0,
|
||||
'discount_amount' => $item['discount_amount'] ?? 0,
|
||||
'batch_no' => $item['batch_no'] ?? null,
|
||||
'expiry_date' => $item['expiry_date'] ?? null,
|
||||
'received_quantity' => $item['received_quantity'] ?? $item['quantity'],
|
||||
'wastage_quantity' => $item['wastage_quantity'] ?? 0,
|
||||
]);
|
||||
|
||||
// Create stock for new item
|
||||
Stock::create([
|
||||
'restaurant_id' => $restaurantId,
|
||||
'ingredient_id' => $item['ingredient_id'],
|
||||
'type' => 'purchase',
|
||||
'quantity' => $item['received_quantity'] ?? $item['quantity'],
|
||||
'unit_cost' => $item['unit_price'],
|
||||
'total_cost' => $item['total_cost'],
|
||||
'reference_type' => 'PurchaseItem',
|
||||
'purchase_id' => $purchaseItem->id,
|
||||
'batch_no' => $item['batch_no'] ?? null,
|
||||
'expiry_date' => $item['expiry_date'] ?? null,
|
||||
'added_by' => $data['created_by'] ?? null,
|
||||
'remarks' => 'Newly added purchase item',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return $this->responseSuccess(
|
||||
$purchase->load('items'),
|
||||
'Purchase has been updated successfully.'
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
DB::rollBack();
|
||||
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
$restaurantId = getUserRestaurantId();
|
||||
|
||||
$purchase = Purchase::where('restaurant_id', $restaurantId)
|
||||
->where('id', $id)
|
||||
->first();
|
||||
|
||||
if (! $purchase) {
|
||||
return $this->responseError([], 'Purchase not found.', 404);
|
||||
}
|
||||
|
||||
// 1️⃣ Delete related Purchase Items + Stock
|
||||
foreach ($purchase->items as $item) {
|
||||
// Delete stock entries created from this item
|
||||
Stock::where('reference_type', 'PurchaseItem')
|
||||
->where('purchase_id', $item->id)
|
||||
->delete();
|
||||
|
||||
// Delete purchase item
|
||||
$item->delete();
|
||||
}
|
||||
|
||||
// 2️⃣ Delete Main Purchase
|
||||
$purchase->delete();
|
||||
|
||||
DB::commit();
|
||||
|
||||
return $this->responseSuccess([], 'Purchase deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
DB::rollBack();
|
||||
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Helper\PurchaseReturnHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\Restaurant\Models\Purchase;
|
||||
use Modules\Restaurant\Models\PurchaseReturn;
|
||||
|
||||
class PurchaseReturnController extends Controller
|
||||
{
|
||||
/**
|
||||
* List purchase returns with pagination, search, and metadata
|
||||
*/
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$filters = $request->all();
|
||||
$data = $this->getAll($filters);
|
||||
|
||||
return $this->responseSuccess($data, 'Purchase returns fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new purchase return
|
||||
*/
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'purchase_id' => 'required|exists:purchases,id',
|
||||
'items' => 'required|array|min:1',
|
||||
'items.*.purchase_item_id' => 'required|exists:purchase_items,id',
|
||||
'items.*.quantity' => 'required|numeric|min:0.01',
|
||||
'items.*.reason' => 'nullable|string|max:255',
|
||||
]);
|
||||
|
||||
try {
|
||||
$purchaseId = $request->purchase_id;
|
||||
$items = $request->items;
|
||||
$userId = auth()->id();
|
||||
|
||||
// Use the helper to process returns
|
||||
$result = PurchaseReturnHelper::processReturn($purchaseId, $items, $userId);
|
||||
|
||||
if (! $result['status']) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => $result['message'],
|
||||
'data' => [],
|
||||
], 400);
|
||||
}
|
||||
|
||||
// Build response with purchase and item details
|
||||
$purchase = Purchase::with(['supplier', 'items.ingredient', 'items.returns.processedBy'])->findOrFail($purchaseId);
|
||||
|
||||
$totals = [
|
||||
'sub_total' => $purchase->items->sum(fn ($i) => $i->quantity * $i->unit_price),
|
||||
'total_returned_quantity' => $purchase->items->sum(fn ($i) => $i->returned_quantity),
|
||||
'total_returned_value' => $purchase->items->sum(fn ($i) => $i->returns->sum(fn ($r) => $r->total_cost)),
|
||||
];
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'message' => 'Purchase return processed successfully.',
|
||||
'data' => [
|
||||
'purchase_id' => $purchase->id,
|
||||
'supplier' => $purchase->supplier,
|
||||
'restaurant' => $purchase->restaurant,
|
||||
'items' => $purchase->items->map(function ($item) {
|
||||
return [
|
||||
'purchase_item_id' => $item->id,
|
||||
'ingredient' => $item->ingredient,
|
||||
'quantity' => $item->quantity,
|
||||
'unit_price' => $item->unit_price,
|
||||
'total_cost' => $item->quantity * $item->unit_price,
|
||||
'received_quantity' => $item->received_quantity,
|
||||
'wastage_quantity' => $item->wastage_quantity,
|
||||
'returned_quantity' => $item->returned_quantity,
|
||||
'batch_no' => $item->batch_no,
|
||||
'expiry_date' => $item->expiry_date,
|
||||
'returns' => $item->returns->map(function ($r) {
|
||||
return [
|
||||
'return_id' => $r->id,
|
||||
'quantity' => $r->quantity,
|
||||
'unit_cost' => $r->unit_cost,
|
||||
'total_cost' => $r->total_cost,
|
||||
'reason' => $r->reason,
|
||||
'return_date' => $r->created_at->toDateString(),
|
||||
'processed_by' => $r->processedBy,
|
||||
];
|
||||
}),
|
||||
];
|
||||
}),
|
||||
'totals' => $totals,
|
||||
],
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => $e->getMessage(),
|
||||
'data' => null,
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show single purchase return
|
||||
*/
|
||||
public function show(int $id): JsonResponse
|
||||
{
|
||||
$return = PurchaseReturn::with(['restaurant', 'purchase', 'purchaseItem', 'ingredient', 'processedBy'])
|
||||
->findOrFail($id);
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'message' => 'Purchase return fetched successfully.',
|
||||
'data' => $return,
|
||||
]);
|
||||
}
|
||||
|
||||
public function getAll(array $filters)
|
||||
{
|
||||
$query = PurchaseReturn::with(['purchase', 'purchaseItem', 'ingredient', 'processedBy']);
|
||||
|
||||
// === Filters ===
|
||||
if (! empty($filters['ingredient_id'])) {
|
||||
$query->where('ingredient_id', $filters['ingredient_id']);
|
||||
}
|
||||
|
||||
if (! empty($filters['purchase_id'])) {
|
||||
$query->where('purchase_id', $filters['purchase_id']);
|
||||
}
|
||||
|
||||
if (! empty($filters['restaurant_id'])) {
|
||||
$query->where('restaurant_id', $filters['restaurant_id']);
|
||||
}
|
||||
|
||||
if (! empty($filters['search'])) {
|
||||
$search = $filters['search'];
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('reason', 'like', "%$search%")
|
||||
->orWhere('batch_no', 'like', "%$search%");
|
||||
});
|
||||
}
|
||||
|
||||
// === Sorting ===
|
||||
$sortBy = $filters['sort_by'] ?? 'return_date';
|
||||
$sortOrder = $filters['sort_order'] ?? 'desc';
|
||||
$query->orderBy($sortBy, $sortOrder);
|
||||
|
||||
// === Pagination ===
|
||||
$perPage = $filters['perPage'] ?? 10;
|
||||
$paginator = $query->paginate($perPage);
|
||||
|
||||
// === Return same structure as Purchase list ===
|
||||
return [
|
||||
'current_page' => $paginator->currentPage(),
|
||||
'data' => $paginator->items(),
|
||||
'first_page_url' => $paginator->url(1),
|
||||
'from' => $paginator->firstItem(),
|
||||
'last_page' => $paginator->lastPage(),
|
||||
'last_page_url' => $paginator->url($paginator->lastPage()),
|
||||
'links' => $paginator->linkCollection(),
|
||||
'next_page_url' => $paginator->nextPageUrl(),
|
||||
'path' => $paginator->path(),
|
||||
'perPage' => $paginator->perPage(),
|
||||
'prev_page_url' => $paginator->previousPageUrl(),
|
||||
'to' => $paginator->lastItem(),
|
||||
'total' => $paginator->total(),
|
||||
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\QRMenuSetting\QRMenuSettingStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\QRMenuSetting\QRMenuSettingUpdateRequest;
|
||||
use Modules\Restaurant\Models\QRMenuSetting;
|
||||
use Modules\Restaurant\Repositories\QRMenuSettingRepository;
|
||||
|
||||
class QRMenuSettingController extends Controller
|
||||
{
|
||||
public function __construct(private QRMenuSettingRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
$qrCode = QRMenuSetting::where('restaurant_id', getUserRestaurantId())->first();
|
||||
|
||||
return $this->responseSuccess($qrCode, 'QRMenuSetting has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(QRMenuSettingStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'QRMenuSetting 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), 'QRMenuSetting has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(QRMenuSettingUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'QRMenuSetting 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), 'QRMenuSetting has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,394 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Modules\Restaurant\Models\Ingredient;
|
||||
use Modules\Restaurant\Models\Purchase;
|
||||
use Modules\Restaurant\Models\PurchaseItem;
|
||||
use Modules\Restaurant\Models\Stock;
|
||||
|
||||
class ReportController extends Controller
|
||||
{
|
||||
/**
|
||||
* Ingredient report (restaurant-wise) with date range and search/filter
|
||||
* GET /api/reports/ingredients
|
||||
* params: restaurant_id, start_date, end_date, search, page, perPage
|
||||
*/
|
||||
public function ingredients(Request $request): JsonResponse
|
||||
{
|
||||
$v = Validator::make($request->all(), [
|
||||
'restaurant_id' => 'nullable|integer|exists:restaurants,id',
|
||||
'start_date' => 'nullable|date',
|
||||
'end_date' => 'nullable|date',
|
||||
'search' => 'nullable|string',
|
||||
'page' => 'nullable|integer',
|
||||
'perPage' => 'nullable|integer',
|
||||
]);
|
||||
|
||||
if ($v->fails()) {
|
||||
return response()->json(['errors' => $v->errors()], 422);
|
||||
}
|
||||
|
||||
$start = $request->input('start_date');
|
||||
$end = $request->input('end_date');
|
||||
$restaurantId = getUserRestaurantId();
|
||||
$search = $request->input('search');
|
||||
$perPage = $request->input('perPage', 25);
|
||||
|
||||
$query = Ingredient::query()
|
||||
->leftJoin('units', 'units.id', '=', 'ingredients.unit_id') // join units
|
||||
->select([
|
||||
'ingredients.id',
|
||||
'ingredients.name',
|
||||
'ingredients.unit_id',
|
||||
'units.name as unit_name', // include unit name
|
||||
'ingredients.cost_per_unit',
|
||||
'ingredients.last_purchase_price',
|
||||
'ingredients.restaurant_id',
|
||||
DB::raw('IFNULL(SUM(stocks_in.quantity),0) as total_in'),
|
||||
DB::raw('IFNULL(SUM(stocks_out.quantity),0) as total_out'),
|
||||
DB::raw('IFNULL(SUM(stocks_in.total_cost),0) as total_in_cost'),
|
||||
])
|
||||
->leftJoin('stocks as stocks_in', function ($join) use ($start, $end, $restaurantId) {
|
||||
$join->on('stocks_in.ingredient_id', '=', 'ingredients.id')
|
||||
->whereIn('stocks_in.type', ['purchase', 'return', 'transfer_in'])
|
||||
->whereNull('stocks_in.deleted_at');
|
||||
|
||||
if ($start) {
|
||||
$join->whereDate('stocks_in.created_at', '>=', $start);
|
||||
}
|
||||
if ($end) {
|
||||
$join->whereDate('stocks_in.created_at', '<=', $end);
|
||||
}
|
||||
if ($restaurantId) {
|
||||
$join->where('stocks_in.restaurant_id', $restaurantId);
|
||||
}
|
||||
})
|
||||
->leftJoin('stocks as stocks_out', function ($join) use ($start, $end, $restaurantId) {
|
||||
$join->on('stocks_out.ingredient_id', '=', 'ingredients.id')
|
||||
->whereIn('stocks_out.type', ['usage', 'damage', 'transfer_out'])
|
||||
->whereNull('stocks_out.deleted_at');
|
||||
|
||||
if ($start) {
|
||||
$join->whereDate('stocks_out.created_at', '>=', $start);
|
||||
}
|
||||
if ($end) {
|
||||
$join->whereDate('stocks_out.created_at', '<=', $end);
|
||||
}
|
||||
if ($restaurantId) {
|
||||
$join->where('stocks_out.restaurant_id', $restaurantId);
|
||||
}
|
||||
})
|
||||
->groupBy([
|
||||
'ingredients.id',
|
||||
'ingredients.name',
|
||||
'ingredients.unit_id',
|
||||
'units.name', // include in groupBy
|
||||
'ingredients.cost_per_unit',
|
||||
'ingredients.last_purchase_price',
|
||||
'ingredients.restaurant_id',
|
||||
]);
|
||||
|
||||
if ($restaurantId) {
|
||||
$query->where('ingredients.restaurant_id', $restaurantId);
|
||||
}
|
||||
|
||||
if ($search) {
|
||||
$query->where('ingredients.name', 'like', "%{$search}%");
|
||||
}
|
||||
|
||||
$paginated = $query->paginate($perPage);
|
||||
|
||||
// Enrich each item with computed fields
|
||||
$paginated->getCollection()->transform(function ($item) use ($start, $restaurantId) {
|
||||
$currentStock = $this->currentStockForIngredient($item->id, $restaurantId);
|
||||
$openingStock = $this->openingStockForIngredient($item->id, $start, $restaurantId);
|
||||
$unitCost = $item->cost_per_unit
|
||||
?: $item->last_purchase_price
|
||||
?: $this->avgUnitCostFromStocks($item->id, $restaurantId);
|
||||
$marketValue = round($currentStock * ($unitCost ?? 0), 2);
|
||||
|
||||
return array_merge($item->toArray(), [
|
||||
'opening_stock' => round($openingStock, 2),
|
||||
'current_stock' => round($currentStock, 2),
|
||||
'estimated_market_value' => $marketValue,
|
||||
]);
|
||||
});
|
||||
|
||||
return $this->responseSuccess($paginated, 'Ingredients report fetched successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Stock report (stock movements) date-to-date
|
||||
* GET /api/reports/stocks
|
||||
* params: restaurant_id, start_date, end_date, ingredient_id, type, page, perPage
|
||||
*/
|
||||
public function stocks(Request $request): JsonResponse
|
||||
{
|
||||
$v = Validator::make($request->all(), [
|
||||
'restaurant_id' => 'nullable|integer|exists:restaurants,id',
|
||||
'start_date' => 'nullable|date',
|
||||
'end_date' => 'nullable|date',
|
||||
'ingredient_id' => 'nullable|integer|exists:ingredients,id',
|
||||
'type' => 'nullable|in:purchase,usage,return,damage,transfer_in,transfer_out',
|
||||
'page' => 'nullable|integer',
|
||||
'perPage' => 'nullable|integer',
|
||||
]);
|
||||
|
||||
if ($v->fails()) {
|
||||
return response()->json(['errors' => $v->errors()], 422);
|
||||
}
|
||||
|
||||
$q = Stock::query()->with(['ingredient'])
|
||||
->when($request->restaurant_id ?? getUserRestaurantId(), fn ($q, $r) => $q->where('restaurant_id', $r))
|
||||
->when($request->ingredient_id, fn ($q, $id) => $q->where('ingredient_id', $id))
|
||||
->when($request->type, fn ($q, $t) => $q->where('type', $t))
|
||||
->when($request->start_date, fn ($q, $s) => $q->whereDate('created_at', '>=', $s))
|
||||
->when($request->end_date, fn ($q, $e) => $q->whereDate('created_at', '<=', $e))
|
||||
->orderBy('created_at', 'desc');
|
||||
|
||||
$perPage = $request->input('perPage', 25);
|
||||
$result = $q->paginate($perPage);
|
||||
|
||||
return $this->responseSuccess($result, 'Stock reports successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Purchase report date-to-date
|
||||
* GET /api/reports/purchases
|
||||
* params: restaurant_id, start_date, end_date, supplier_id, payment_status
|
||||
*/
|
||||
public function purchases(Request $request): JsonResponse
|
||||
{
|
||||
$v = Validator::make($request->all(), [
|
||||
'restaurant_id' => 'nullable|integer|exists:restaurants,id',
|
||||
'supplier_id' => 'nullable|integer|exists:suppliers,id',
|
||||
'start_date' => 'nullable|date',
|
||||
'end_date' => 'nullable|date',
|
||||
'payment_status' => 'nullable|in:paid,unpaid,partial',
|
||||
'page' => 'nullable|integer',
|
||||
'perPage' => 'nullable|integer',
|
||||
]);
|
||||
if ($v->fails()) {
|
||||
return response()->json(['errors' => $v->errors()], 422);
|
||||
}
|
||||
|
||||
$q = Purchase::with(['supplier', 'items.ingredient'])
|
||||
->when($request->restaurant_id ?? getUserRestaurantId(), fn ($q, $r) => $q->where('restaurant_id', $r))
|
||||
->when($request->supplier_id, fn ($q, $s) => $q->where('supplier_id', $s))
|
||||
->when($request->payment_status, fn ($q, $p) => $q->where('payment_status', $p))
|
||||
->when($request->start_date, fn ($q, $s) => $q->whereDate('purchase_date', '>=', $s))
|
||||
->when($request->end_date, fn ($q, $e) => $q->whereDate('purchase_date', '<=', $e))
|
||||
->orderBy('purchase_date', 'desc');
|
||||
|
||||
$perPage = $request->input('perPage', 25);
|
||||
$res = $q->paginate($perPage);
|
||||
|
||||
return $this->responseSuccess($res, 'Purchase reports successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Purchase ingredient with sales items countable for sales-estimate report
|
||||
* Combines purchases and sold menu items to estimate ingredient usage & profitability
|
||||
* GET /api/reports/purchase-estimate
|
||||
* params: restaurant_id, start_date, end_date
|
||||
*/
|
||||
public function purchaseEstimate(Request $request): JsonResponse
|
||||
{
|
||||
$v = Validator::make($request->all(), [
|
||||
'restaurant_id' => 'nullable|integer|exists:restaurants,id',
|
||||
'start_date' => 'required|date',
|
||||
'end_date' => 'required|date',
|
||||
]);
|
||||
if ($v->fails()) {
|
||||
return response()->json(['errors' => $v->errors()], 422);
|
||||
}
|
||||
|
||||
$start = date('Y-m-d', strtotime($request->start_date));
|
||||
$end = date('Y-m-d', strtotime($request->end_date));
|
||||
$restaurantId = $request->restaurant_id ?? getUserRestaurantId();
|
||||
|
||||
// 🛒 Purchased quantities per ingredient
|
||||
$purchases = PurchaseItem::select(
|
||||
'ingredient_id',
|
||||
DB::raw('SUM(received_quantity) as purchased_qty'),
|
||||
DB::raw('SUM(total_cost) as purchased_cost')
|
||||
)
|
||||
->when($restaurantId, fn ($q, $r) => $q->where('restaurant_id', $r))
|
||||
->whereBetween(DB::raw('DATE(created_at)'), [$start, $end])
|
||||
->groupBy('ingredient_id')
|
||||
->get()
|
||||
->keyBy('ingredient_id');
|
||||
|
||||
// 🍽️ Estimate ingredient usage from sales
|
||||
$salesEstimate = DB::table('order_items')
|
||||
->select(
|
||||
'food_variant_ingredients.ingredient_id',
|
||||
DB::raw('SUM(order_items.quantity * food_variant_ingredients.quantity * (1 + food_variant_ingredients.wastage_percentage / 100)) as estimated_used')
|
||||
)
|
||||
->join('food_variants', 'order_items.food_variant_id', '=', 'food_variants.id')
|
||||
->join('food_variant_ingredients', 'food_variant_ingredients.food_variant_id', '=', 'food_variants.id')
|
||||
->when($restaurantId, fn ($q, $r) => $q->where('order_items.restaurant_id', $r))
|
||||
->whereBetween(DB::raw('DATE(order_items.created_at)'), [$start, $end])
|
||||
->groupBy('food_variant_ingredients.ingredient_id')
|
||||
->get()
|
||||
->keyBy('ingredient_id');
|
||||
|
||||
// 🧾 Merge purchase + estimated usage
|
||||
$ingredientIds = collect(array_unique(array_merge(
|
||||
$purchases->keys()->toArray(),
|
||||
$salesEstimate->keys()->toArray()
|
||||
)));
|
||||
|
||||
$report = [];
|
||||
foreach ($ingredientIds as $ingId) {
|
||||
$ingredient = Ingredient::find($ingId);
|
||||
$p = $purchases->get($ingId);
|
||||
$s = $salesEstimate->get($ingId);
|
||||
|
||||
$pQty = $p->purchased_qty ?? 0;
|
||||
$pCost = $p->purchased_cost ?? 0;
|
||||
$used = $s->estimated_used ?? 0;
|
||||
$remaining = max(0, $pQty - $used);
|
||||
|
||||
$unitCost = $ingredient->cost_per_unit
|
||||
?: ($pQty ? ($pCost / $pQty) : ($ingredient->last_purchase_price ?? 0));
|
||||
|
||||
$report[] = [
|
||||
'ingredient_id' => $ingId,
|
||||
'ingredient_name' => $ingredient->name ?? 'Unknown',
|
||||
'purchased_qty' => (float) $pQty,
|
||||
'purchased_cost' => (float) $pCost,
|
||||
'estimated_used' => (float) $used,
|
||||
'estimated_remaining' => (float) $remaining,
|
||||
'unit_cost_used' => round($unitCost, 2),
|
||||
'estimated_remaining_value' => round($remaining * $unitCost, 2),
|
||||
];
|
||||
}
|
||||
|
||||
return $this->responseSuccess([
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
'data' => $report,
|
||||
], 'Purchase Estimate reports successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Opening stock (date-to-date): returns opening stock at start_date, current stock and market value
|
||||
* GET /api/reports/opening-stock
|
||||
* params: restaurant_id, start_date, end_date, ingredient_id
|
||||
*/
|
||||
public function openingStock(Request $request): JsonResponse
|
||||
{
|
||||
$v = Validator::make($request->all(), [
|
||||
'restaurant_id' => 'nullable|integer|exists:restaurants,id',
|
||||
'ingredient_id' => 'nullable|integer|exists:ingredients,id',
|
||||
'start_date' => 'required|date',
|
||||
'end_date' => 'nullable|date',
|
||||
]);
|
||||
if ($v->fails()) {
|
||||
return response()->json(['errors' => $v->errors()], 422);
|
||||
}
|
||||
|
||||
$start = $request->start_date;
|
||||
$restaurantId = $request->restaurant_id ?? getUserRestaurantId();
|
||||
|
||||
$ingQuery = Ingredient::query()->when($request->ingredient_id, fn ($q, $id) => $q->where('id', $id))
|
||||
->when($restaurantId, fn ($q, $r) => $q->where('restaurant_id', $r));
|
||||
|
||||
$results = $ingQuery->get()->map(function ($ingredient) use ($start, $restaurantId) {
|
||||
$opening = $this->openingStockForIngredient($ingredient->id, $start, $restaurantId);
|
||||
$current = $this->currentStockForIngredient($ingredient->id, $restaurantId);
|
||||
$unitCost = $ingredient->cost_per_unit ?: $ingredient->last_purchase_price ?: $this->avgUnitCostFromStocks($ingredient->id, $restaurantId);
|
||||
$marketValue = round($current * ($unitCost ?? 0), 2);
|
||||
|
||||
return [
|
||||
'ingredient_id' => $ingredient->id,
|
||||
'ingredient_name' => $ingredient->name,
|
||||
'opening_stock' => round($opening, 2),
|
||||
'current_stock' => round($current, 2),
|
||||
'unit_cost' => round($unitCost ?? 0, 2),
|
||||
'market_value' => $marketValue,
|
||||
];
|
||||
});
|
||||
|
||||
return $this->responseSuccess(['start_date' => $start, 'data' => $results], 'Opening Stock reports successfully.');
|
||||
}
|
||||
|
||||
// ---------------- Helper methods ----------------
|
||||
|
||||
/**
|
||||
* Calculate opening stock for ingredient before the given date (exclusive)
|
||||
*/
|
||||
protected function openingStockForIngredient($ingredientId, $startDate = null, $restaurantId = null): float|int
|
||||
{
|
||||
if (! $startDate) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$pos = ['purchase', 'return', 'transfer_in'];
|
||||
$neg = ['usage', 'damage', 'transfer_out'];
|
||||
|
||||
$q = Stock::where('ingredient_id', $ingredientId)->whereDate('created_at', '<', $startDate)->whereNull('deleted_at');
|
||||
if ($restaurantId) {
|
||||
$q->where('restaurant_id', $restaurantId);
|
||||
}
|
||||
|
||||
$in = (float) $q->whereIn('type', $pos)->sum('quantity');
|
||||
$out = (float) $q->whereIn('type', $neg)->sum('quantity');
|
||||
|
||||
return $in - $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Current stock calculated from stocks table (fallback to ingredients.stock_quantity)
|
||||
*/
|
||||
protected function currentStockForIngredient($ingredientId, $restaurantId = null): float|int
|
||||
{
|
||||
$pos = ['purchase', 'return', 'transfer_in'];
|
||||
$neg = ['usage', 'damage', 'transfer_out'];
|
||||
|
||||
$q = Stock::where('ingredient_id', $ingredientId)->whereNull('deleted_at');
|
||||
if ($restaurantId) {
|
||||
$q->where('restaurant_id', $restaurantId);
|
||||
}
|
||||
|
||||
$in = (float) $q->whereIn('type', $pos)->sum('quantity');
|
||||
$out = (float) $q->whereIn('type', $neg)->sum('quantity');
|
||||
|
||||
$delta = $in - $out;
|
||||
|
||||
// fallback to ingredients.stock_quantity if stocks table is sparse
|
||||
$ingredient = Ingredient::find($ingredientId);
|
||||
$ingQty = $ingredient ? (float) $ingredient->stock_quantity : 0;
|
||||
|
||||
// Use the most reliable value: if ingredient.stock_quantity > 0, assume it's authoritative
|
||||
if ($ingQty > 0) {
|
||||
return $ingQty;
|
||||
}
|
||||
|
||||
return $delta;
|
||||
}
|
||||
|
||||
protected function avgUnitCostFromStocks($ingredientId, $restaurantId = null): float|int|null
|
||||
{
|
||||
$q = Stock::where('ingredient_id', $ingredientId)->whereNotNull('unit_cost')->whereNull('deleted_at');
|
||||
if ($restaurantId) {
|
||||
$q->where('restaurant_id', $restaurantId);
|
||||
}
|
||||
|
||||
$totalQty = (float) $q->sum('quantity');
|
||||
$totalCost = (float) $q->sum('total_cost');
|
||||
|
||||
if ($totalQty <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $totalCost / $totalQty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\Authenticatable;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\Restaurant\Models\Reservation;
|
||||
use Modules\Restaurant\Repositories\ReservationRepository;
|
||||
|
||||
class ReservationController extends Controller
|
||||
{
|
||||
public function __construct(private ReservationRepository $repo) {}
|
||||
|
||||
use Authenticatable;
|
||||
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$filters = $request->all();
|
||||
$data = $this->repo->getAll($filters);
|
||||
|
||||
return $this->responseSuccess($data, 'Reservation list fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$validated = $request->validate([
|
||||
'table_id' => 'required|integer|exists:tables,id',
|
||||
'customer_id' => 'nullable|integer|exists:customers,id',
|
||||
'reservation_date' => 'required|date',
|
||||
'start_time' => 'required|date_format:H:i',
|
||||
'end_time' => 'required|date_format:H:i|after:start_time',
|
||||
'people_count' => 'required|integer|min:1',
|
||||
'status' => 'nullable|in:booked,free,upcoming,cancelled',
|
||||
'note' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$validated['restaurant_id'] = $this->getCurrentRestaurantId();
|
||||
$data = $this->repo->store($validated);
|
||||
|
||||
// TODO
|
||||
// $user = auth()->user();
|
||||
// // Action Log info
|
||||
// $this->trackAction(ActionStatus::OrderCreate, User::class, $user->id, $order);
|
||||
|
||||
// // Push Notification
|
||||
// if ($user?->fcm_token) {
|
||||
// $result = $firebase->sendNotification(
|
||||
// $user->fcm_token,
|
||||
// 'Order Confirmed',
|
||||
// "Your order #{$order->id} has been confirmed!",
|
||||
// ['order_id' => $order->id]
|
||||
// );
|
||||
|
||||
// if ($result === true) {
|
||||
// return response()->json(['message' => 'Notification sent successfully']);
|
||||
// } else {
|
||||
// return response()->json(['message' => 'Failed to send notification', 'error' => $result], 500);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Prepare data for markdown email
|
||||
// $data = [
|
||||
// 'customer_name' => $order->customer->name ?? 'Valued Customer',
|
||||
// 'order_id' => $order->tracking_number,
|
||||
// 'order_date' => Carbon::parse($order->created_at)->format('d-m-Y'),
|
||||
// 'payment_method' => $order->payment_method ?? 'N/A',
|
||||
// 'order_status' => $order->order_status ?? 'Pending',
|
||||
// 'products' => $products,
|
||||
// 'subtotal' => $order->amount ?? 0,
|
||||
// 'shipping_cost' => $order->delivery_fee ?? 0,
|
||||
// 'total_amount' => $order->paid_total ?? 0,
|
||||
// 'customer_address' => $order->shipping_address ?? 'N/A',
|
||||
// 'store_name' => get_setting('company_name', $restaurant_id) ?? 'Our Store',
|
||||
// ];
|
||||
// Directly send email
|
||||
// $result = shop_mailer_send($order->restaurant_id, $order->customer?->email, new OrderInvoiceMail($data));
|
||||
// if (! $result['status']) {
|
||||
// Log::warning("Order invoice email not sent for shop {$order->restaurant_id}: " . $result['message']);
|
||||
// }
|
||||
// Mail::to($email)->send(new OrderInvoiceMail($data));
|
||||
|
||||
return $this->responseSuccess($data, 'Reservation created successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function show(int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
$reservation = Reservation::with(['table', 'customer'])->findOrFail($id);
|
||||
|
||||
return $this->responseSuccess($reservation, 'Reservation details fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(Request $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
$reservation = Reservation::findOrFail($id);
|
||||
|
||||
$validated = $request->validate([
|
||||
'status' => 'nullable|in:booked,free,upcoming,cancelled',
|
||||
'note' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$reservation->update($validated);
|
||||
|
||||
return $this->responseSuccess($reservation, 'Reservation updated successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
$reservation = Reservation::findOrFail($id);
|
||||
$reservation->delete();
|
||||
|
||||
return $this->responseSuccess([], 'Reservation deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\ReservationSetting\ReservationSettingStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\ReservationSetting\ReservationSettingUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\ReservationSettingRepository;
|
||||
|
||||
class ReservationSettingController extends Controller
|
||||
{
|
||||
public function __construct(private ReservationSettingRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'ReservationSetting has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(ReservationSettingStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'ReservationSetting 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), 'ReservationSetting has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(ReservationSettingUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'ReservationSetting 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), 'ReservationSetting has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\Authenticatable;
|
||||
use Exception;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\Restaurant\Models\ReservationUnavailable;
|
||||
|
||||
class ReservationUnavailableController extends Controller
|
||||
{
|
||||
use Authenticatable;
|
||||
|
||||
/**
|
||||
* Display a listing of unavailable tables.
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$query = ReservationUnavailable::with('table');
|
||||
|
||||
if ($request->filled('table_id')) {
|
||||
$query->where('table_id', $request->table_id);
|
||||
}
|
||||
|
||||
if ($request->filled('date')) {
|
||||
$query->where('date', $request->date);
|
||||
}
|
||||
|
||||
$data = $query->latest()->paginate($request->get('perPage', 10));
|
||||
|
||||
return $this->responseSuccess($data, 'Unavailable table list fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new unavailable record.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$validated = $request->validate([
|
||||
'table_id' => 'required|exists:tables,id',
|
||||
'date' => 'required|date',
|
||||
'start_time' => 'required|date_format:H:i',
|
||||
'end_time' => 'required|date_format:H:i|after:start_time',
|
||||
'reason' => 'nullable|string|max:255',
|
||||
'is_recurring' => 'boolean',
|
||||
]);
|
||||
|
||||
$validated['restaurant_id'] = $this->getCurrentRestaurantId();
|
||||
$data = ReservationUnavailable::create($validated);
|
||||
|
||||
return $this->responseSuccess($data, 'Table marked as unavailable successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show unavailable table details.
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
try {
|
||||
$record = ReservationUnavailable::with('table')->findOrFail($id);
|
||||
|
||||
return $this->responseSuccess($record, 'Unavailable record details fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update unavailable record.
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
try {
|
||||
$record = ReservationUnavailable::findOrFail($id);
|
||||
|
||||
$validated = $request->validate([
|
||||
'table_id' => 'sometimes|exists:tables,id',
|
||||
'date' => 'sometimes|date',
|
||||
'start_time' => 'sometimes|date_format:H:i',
|
||||
'end_time' => 'sometimes|date_format:H:i|after:start_time',
|
||||
'reason' => 'nullable|string|max:255',
|
||||
'is_recurring' => 'boolean',
|
||||
]);
|
||||
|
||||
$record->update($validated);
|
||||
|
||||
return $this->responseSuccess($record, 'Unavailable record updated successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete unavailable record.
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
try {
|
||||
$record = ReservationUnavailable::findOrFail($id);
|
||||
$record->delete();
|
||||
|
||||
return $this->responseSuccess([], 'Unavailable record removed successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\Restaurant\Http\Requests\RestaurantSchedule\RestaurantScheduleStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\RestaurantSchedule\RestaurantScheduleUpdateRequest;
|
||||
use Modules\Restaurant\Models\RestaurantSchedule;
|
||||
|
||||
class RestaurantScheduleController extends Controller
|
||||
{
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$perPage = $request->input('perPage', 15);
|
||||
$sortBy = $request->input('sortBy', 'id');
|
||||
$sortDir = $request->input('sortDir', 'desc');
|
||||
$search = $request->input('search');
|
||||
|
||||
$query = RestaurantSchedule::query()
|
||||
->with('times:id,restaurant_schedule_id,open_time,close_time')
|
||||
->where('restaurant_id', getUserRestaurantId());
|
||||
|
||||
// 🔍 Search Filter
|
||||
if (! empty($search)) {
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('day', 'LIKE', "%{$search}%")
|
||||
->orWhere('start_date', 'LIKE', "%{$search}%")
|
||||
->orWhere('end_date', 'LIKE', "%{$search}%");
|
||||
});
|
||||
}
|
||||
|
||||
// 🔽 Sorting
|
||||
$query->orderBy($sortBy, $sortDir);
|
||||
|
||||
// 📄 Pagination
|
||||
$data = $query->paginate($perPage)->appends($request->query());
|
||||
|
||||
return $this->responseSuccess($data, 'Restaurant schedule retrieved successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(RestaurantScheduleStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
foreach ($request->schedules as $item) {
|
||||
|
||||
// Create / Update
|
||||
$schedule = RestaurantSchedule::updateOrCreate([
|
||||
'restaurant_id' => getUserRestaurantId(),
|
||||
'day' => $item['day'],
|
||||
], [
|
||||
'is_open' => $item['is_open'] ?? true,
|
||||
]);
|
||||
|
||||
// Clean old times
|
||||
$schedule->times()->delete();
|
||||
|
||||
// Add new slots
|
||||
foreach ($item['times'] as $slot) {
|
||||
$schedule->times()->create([
|
||||
'open_time' => $slot['open_time'],
|
||||
'close_time' => $slot['close_time'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->responseSuccess([], 'Restaurant schedule added successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function show(int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
$data = RestaurantSchedule::with('times')->findOrFail($id);
|
||||
|
||||
return $this->responseSuccess($data, 'Schedule retrieved successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(RestaurantScheduleUpdateRequest $request, $restaurantId): JsonResponse
|
||||
{
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
foreach ($request->schedules as $item) {
|
||||
|
||||
// Find existing schedule day or create new
|
||||
$schedule = RestaurantSchedule::firstOrCreate(
|
||||
[
|
||||
'restaurant_id' => $restaurantId,
|
||||
'day' => $item['day'],
|
||||
],
|
||||
['is_open' => $item['is_open'] ?? true]
|
||||
);
|
||||
|
||||
// Update is_open if changed
|
||||
$schedule->update(['is_open' => $item['is_open'] ?? true]);
|
||||
|
||||
// Existing time slots
|
||||
$existingTimes = $schedule->times()->get();
|
||||
|
||||
$newTimes = collect($item['times']);
|
||||
|
||||
// Delete removed slots
|
||||
$existingTimes->each(function ($slot) use ($newTimes) {
|
||||
if (! $newTimes->contains(fn ($t) => $t['open_time'] == $slot->open_time && $t['close_time'] == $slot->close_time)) {
|
||||
$slot->delete();
|
||||
}
|
||||
});
|
||||
|
||||
// Add or update new slots
|
||||
foreach ($item['times'] as $slot) {
|
||||
$schedule->times()->updateOrCreate(
|
||||
[
|
||||
'open_time' => $slot['open_time'],
|
||||
'close_time' => $slot['close_time'],
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return $this->responseSuccess([], 'Restaurant schedule updated successfully (attach/detach).');
|
||||
} catch (Exception $e) {
|
||||
DB::rollBack();
|
||||
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
$schedule = RestaurantSchedule::findOrFail($id);
|
||||
$schedule->times()->delete();
|
||||
$schedule->delete();
|
||||
|
||||
return $this->responseSuccess([], 'Schedule deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\RequestSanitizerTrait;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\Supplier\SupplierStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\Supplier\SupplierUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\SupplierRepository;
|
||||
|
||||
class SupplierController extends Controller
|
||||
{
|
||||
use RequestSanitizerTrait;
|
||||
|
||||
public function __construct(private SupplierRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'Supplier has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(SupplierStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'Supplier 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), 'Supplier has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(SupplierUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'Supplier 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), 'Supplier has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\RequestSanitizerTrait;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\Table\TableStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\Table\TableUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\TableRepository;
|
||||
|
||||
class TableController extends Controller
|
||||
{
|
||||
use RequestSanitizerTrait;
|
||||
|
||||
public function __construct(private TableRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'Table has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(TableStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'Table 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), 'Table has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(TableUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'Table 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), 'Table has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\TaxSetting\TaxSettingStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\TaxSetting\TaxSettingUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\TaxSettingRepository;
|
||||
|
||||
class TaxSettingController extends Controller
|
||||
{
|
||||
public function __construct(private TaxSettingRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'TaxSetting has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(TaxSettingStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'TaxSetting 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), 'TaxSetting has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(TaxSettingUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'TaxSetting 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), 'TaxSetting has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\Unit\UnitStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\Unit\UnitUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\UnitRepository;
|
||||
|
||||
class UnitController extends Controller
|
||||
{
|
||||
public function __construct(private UnitRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'Unit has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(UnitStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'Unit 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), 'Unit has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(UnitUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'Unit 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), 'Unit has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Restaurant\Http\Requests\Zone\ZoneStoreRequest;
|
||||
use Modules\Restaurant\Http\Requests\Zone\ZoneUpdateRequest;
|
||||
use Modules\Restaurant\Repositories\ZoneRepository;
|
||||
|
||||
class ZoneController extends Controller
|
||||
{
|
||||
public function __construct(private ZoneRepository $repo) {}
|
||||
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->getAll(request()->all()), 'Zone has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function store(ZoneStoreRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->create($request->all()), 'Zone 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), 'Zone has been fetched successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function update(ZoneUpdateRequest $request, int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
return $this->responseSuccess($this->repo->update($id, $request->all()), 'Zone 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), 'Zone has been deleted successfully.');
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\Addon;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class AddonStoreRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => 'required|string|max:255',
|
||||
'price' => 'required|numeric|min:0|max:999999.99',
|
||||
'vat' => 'nullable|numeric|min:0|max:99.99',
|
||||
'pst' => 'nullable|numeric|min:0|max:99.99',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\Addon;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class AddonUpdateRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => 'required|string|max:255',
|
||||
'price' => 'required|numeric|min:0|max:999999.99',
|
||||
'vat' => 'nullable|numeric|min:0|max:99.99',
|
||||
'pst' => 'nullable|numeric|min:0|max:99.99',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\AddonFood;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class AddonFoodStoreRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'addon_id' => 'required|integer|exists:addons,id',
|
||||
'food_item_id' => 'required|integer|exists:food_items,id',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\AddonFood;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class AddonFoodUpdateRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'addon_id' => 'required|integer|exists:addons,id',
|
||||
'food_item_id' => 'required|integer|exists:food_items,id',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\Customer;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class CustomerStoreRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => 'required|string|max:255',
|
||||
'email' => 'nullable|email|max:255',
|
||||
'phone' => 'nullable|string|max:20',
|
||||
'address' => 'nullable|string|max:255',
|
||||
'avatar' => 'nullable|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
|
||||
'status' => 'nullable|boolean',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\Customer;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class CustomerUpdateRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => 'required|string|max:255',
|
||||
'email' => 'nullable|email|max:255',
|
||||
'phone' => 'nullable|string|max:20',
|
||||
'address' => 'nullable|string|max:255',
|
||||
'avatar' => 'nullable|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
|
||||
'status' => 'nullable|boolean',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\CustomerAddress;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class CustomerAddressStoreRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
// validation rules
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\CustomerAddress;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class CustomerAddressUpdateRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
// validation rules
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\DeliveryCharge;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class DeliveryChargeStoreRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
// validation rules
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\DeliveryCharge;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class DeliveryChargeUpdateRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
// validation rules
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\FoodAvailability;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class FoodAvailabilityStoreRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'food_item_id' => 'required|exists:food_items,id',
|
||||
'availability' => 'required|array|min:1',
|
||||
'availability.*.day' => 'required|in:Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday',
|
||||
'availability.*.times' => 'required|array|min:1',
|
||||
'availability.*.times.*.open_time' => 'required|date_format:H:i',
|
||||
'availability.*.times.*.close_time' => 'required|date_format:H:i|after:availability.*.times.*.open_time',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\FoodAvailability;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class FoodAvailabilityUpdateRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'availability' => 'required|array|min:1',
|
||||
'availability.*.day' => 'required|in:Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday',
|
||||
'availability.*.times' => 'required|array|min:1',
|
||||
'availability.*.times.*.open_time' => 'required|date_format:H:i',
|
||||
'availability.*.times.*.close_time' => 'required|date_format:H:i|after:availability.*.times.*.open_time',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\FoodCategory;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class FoodCategoryStoreRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => 'required|string|max:255',
|
||||
'image' => 'nullable|image|mimes:jpeg,png,jpg,webp|max:2048', // for file upload
|
||||
'parent_id' => 'nullable|exists:food_categories,id',
|
||||
'is_offer' => 'nullable|boolean',
|
||||
'start_date' => 'nullable|date|before_or_equal:end_date',
|
||||
'end_date' => 'nullable|date|after_or_equal:start_date',
|
||||
'status' => 'nullable|in:0,1',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\FoodCategory;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class FoodCategoryUpdateRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => 'required|string|max:255',
|
||||
'image' => 'nullable|image|mimes:jpeg,png,jpg,webp|max:2048', // for file upload
|
||||
'parent_id' => 'nullable|exists:food_categories,id',
|
||||
'is_offer' => 'nullable|boolean',
|
||||
'start_date' => 'nullable|date|before_or_equal:end_date',
|
||||
'end_date' => 'nullable|date|after_or_equal:start_date',
|
||||
'status' => 'nullable|in:0,1',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\FoodItem;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class FoodItemStoreRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'category_id' => 'required|exists:food_categories,id',
|
||||
'menu_category_id' => 'nullable|exists:menu_categories,id',
|
||||
'menu_section_id' => 'nullable|exists:menu_sections,id',
|
||||
'name' => 'required|string|max:255',
|
||||
'slug' => 'nullable|string|max:255|unique:food_items,slug',
|
||||
'description' => 'nullable|string',
|
||||
'points' => 'nullable',
|
||||
'food_type' => 'required|in:Veg,Non-Veg',
|
||||
'is_featured' => 'nullable',
|
||||
'is_party' => 'nullable',
|
||||
'is_dinner' => 'nullable',
|
||||
'is_lunch' => 'nullable',
|
||||
'is_popular_item' => 'nullable',
|
||||
'is_chef_special' => 'nullable',
|
||||
'prep_time' => [
|
||||
'nullable',
|
||||
'regex:/^\d{2}:\d{2}(:\d{2})?$/',
|
||||
],
|
||||
'cooking_time' => [
|
||||
'nullable',
|
||||
'regex:/^\d{2}:\d{2}(:\d{2})?$/',
|
||||
],
|
||||
'vat' => 'nullable',
|
||||
'pst' => 'nullable',
|
||||
'ingredients_cost' => 'nullable',
|
||||
'allergens' => 'nullable|string|max:255',
|
||||
'notes' => 'nullable|string',
|
||||
'image' => 'nullable|image|mimes:jpg,jpeg,png|max:2048',
|
||||
|
||||
'variants' => 'required|array|min:1',
|
||||
'variants.*.name' => 'required|string|max:255',
|
||||
'variants.*.price' => 'required',
|
||||
'variants.*.offer_price' => 'nullable',
|
||||
'variants.*.discount' => 'nullable',
|
||||
'variants.*.unit_id' => [
|
||||
'required',
|
||||
Rule::exists('units', 'id')->whereNull('deleted_at'),
|
||||
],
|
||||
'variants.*.is_default' => 'required',
|
||||
'variants.*.stock_tracking' => 'nullable',
|
||||
'variants.*.ingredients_cost' => 'nullable',
|
||||
'variants.*.profit_margin' => 'nullable',
|
||||
'variants.*.alert_stock_quantity' => 'nullable',
|
||||
'variants.*.combo_type' => 'nullable|in:single,combo,add-on',
|
||||
'variants.*.is_active_offer' => 'nullable',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\FoodItem;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class FoodItemUpdateRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'category_id' => 'required|exists:food_categories,id',
|
||||
'menu_category_id' => 'nullable|exists:menu_categories,id',
|
||||
'menu_section_id' => 'nullable|exists:menu_sections,id',
|
||||
'name' => 'required|string|max:255',
|
||||
'points' => 'nullable',
|
||||
'food_type' => 'required|in:Veg,Non-Veg',
|
||||
'is_party' => 'nullable',
|
||||
'is_dinner' => 'nullable',
|
||||
'is_lunch' => 'nullable',
|
||||
'is_popular_item' => 'nullable',
|
||||
'is_chef_special' => 'nullable',
|
||||
'cooking_time' => 'required',
|
||||
'components' => 'nullable|string',
|
||||
'variants' => 'required|array|min:1',
|
||||
'variants.*.name' => 'required|string|max:255',
|
||||
'variants.*.price' => 'required',
|
||||
'variants.*.unit_id' => [
|
||||
'required',
|
||||
Rule::exists('units', 'id')->whereNull('deleted_at'),
|
||||
],
|
||||
'variants.*.is_default' => 'required',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\FoodReview;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class FoodReviewStoreRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'food_item_id' => 'required|integer|exists:food_items,id',
|
||||
'rating' => 'required|integer|min:1|max:5',
|
||||
'review' => 'required|string',
|
||||
'images.*' => 'nullable|image|max:2048',
|
||||
'video_url' => 'nullable|url',
|
||||
'video_file' => 'nullable|mimes:mp4,webm,mov|max:20480',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\FoodReview;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class FoodReviewUpdateRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'rating' => 'required|integer|min:1|max:5',
|
||||
'review' => 'required|string',
|
||||
'images.*' => 'nullable|image|max:2048',
|
||||
'video_url' => 'nullable|url',
|
||||
'video_file' => 'nullable|mimes:mp4,webm,mov|max:20480',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\FoodReviewReply;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class FoodReviewReplyStoreRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'review_id' => 'required|exists:food_reviews,id',
|
||||
'message' => 'nullable|string',
|
||||
'attachments.*' => 'nullable|file|mimes:jpg,jpeg,png,pdf,docx,mp4,webm|max:20480', // 20MB max
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\FoodReviewReply;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class FoodReviewReplyUpdateRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'message' => 'nullable|string',
|
||||
'attachments.*' => 'nullable|file|mimes:jpg,jpeg,png,pdf,docx,mp4,webm|max:20480',
|
||||
'remove_attachments' => 'nullable|array', // names of attachments to remove
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\FoodVariant;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class FoodVariantStoreRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'food_item_id' => 'required|integer|exists:food_items,id',
|
||||
'unit_id' => 'required|exists:units,id',
|
||||
'name' => 'required|string|max:255',
|
||||
'price' => 'required|numeric|min:0|max:999999.99',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\FoodVariant;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class FoodVariantUpdateRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'food_item_id' => 'required|integer|exists:food_items,id',
|
||||
'unit_id' => 'required|exists:units,id',
|
||||
'name' => 'required|string|max:255',
|
||||
'price' => 'required|numeric|min:0|max:999999.99',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\FoodVariantIngredient;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class FoodVariantIngredientStoreRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'food_variant_id' => 'required|exists:food_variants,id',
|
||||
'ingredients' => 'required|array|min:1',
|
||||
'ingredients.*.ingredient_id' => 'required|exists:ingredients,id',
|
||||
'ingredients.*.quantity' => 'required|numeric|min:0',
|
||||
'ingredients.*.wastage_percentage' => 'nullable|numeric|min:0',
|
||||
'ingredients.*.unit_conversion_factor' => 'nullable|numeric|min:0',
|
||||
'ingredients.*.optional' => 'nullable|in:Y,N',
|
||||
'ingredients.*.notes' => 'nullable|string',
|
||||
'ingredients.*.status' => 'nullable|in:0,1',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\FoodVariantIngredient;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class FoodVariantIngredientUpdateRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'food_variant_id' => 'sometimes|required|exists:food_variants,id',
|
||||
'ingredient_id' => 'sometimes|required|exists:ingredients,id',
|
||||
'quantity' => 'sometimes|required|numeric|min:0',
|
||||
'wastage_percentage' => 'nullable|numeric|min:0',
|
||||
'unit_conversion_factor' => 'nullable|numeric|min:0',
|
||||
'optional' => 'nullable|in:Y,N',
|
||||
'notes' => 'nullable|string',
|
||||
'status' => 'nullable|in:0,1',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\FoodWaste;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class FoodWasteStoreRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'food_item_id' => 'required|exists:food_items,id',
|
||||
'food_variant_id' => 'nullable|exists:food_variants,id',
|
||||
'quantity' => 'required|numeric|min:0.01',
|
||||
'reason' => 'required|string|max:255',
|
||||
'notes' => 'nullable|string',
|
||||
'wasted_at' => 'nullable|date',
|
||||
'approve' => 'nullable|boolean',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\FoodWaste;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class FoodWasteUpdateRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'food_item_id' => 'required|exists:food_items,id',
|
||||
'food_variant_id' => 'nullable|exists:food_variants,id',
|
||||
'quantity' => 'required|numeric|min:0.01',
|
||||
'reason' => 'required|string|max:255',
|
||||
'notes' => 'nullable|string',
|
||||
'wasted_at' => 'nullable|date',
|
||||
'approve' => 'nullable|boolean',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\Ingredient;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class IngredientStoreRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
// ===== Basic Info =====
|
||||
'name' => 'required|string|max:255',
|
||||
'unit_id' => 'required|exists:units,id',
|
||||
'stock_quantity' => 'nullable|numeric|min:0',
|
||||
'cost_per_unit' => 'nullable|numeric|min:0',
|
||||
'low_stock_alert' => 'nullable|numeric|min:0',
|
||||
'image' => 'nullable|image',
|
||||
|
||||
// ===== Supplier & Purchase Info =====
|
||||
'supplier_id' => 'nullable|exists:suppliers,id',
|
||||
'last_purchase_price' => 'nullable|numeric|min:0',
|
||||
'last_purchase_date' => 'nullable|date',
|
||||
|
||||
// ===== Units & Conversions =====
|
||||
'conversion_factor' => 'nullable|numeric|min:0.01',
|
||||
|
||||
// ===== Stock & Inventory =====
|
||||
'reserved_quantity' => 'nullable|numeric|min:0',
|
||||
'wastage_quantity' => 'nullable|numeric|min:0',
|
||||
|
||||
// ===== Categorization =====
|
||||
'category' => 'nullable|string|max:100',
|
||||
'notes' => 'nullable|string|max:2000',
|
||||
|
||||
// ===== Status =====
|
||||
'status' => 'nullable|in:0,1',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Restaurant\Http\Requests\Ingredient;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class IngredientUpdateRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
// ===== Basic Info =====
|
||||
'name' => 'required|string|max:255',
|
||||
'unit_id' => 'required|exists:units,id',
|
||||
'stock_quantity' => 'nullable|numeric|min:0',
|
||||
'cost_per_unit' => 'nullable|numeric|min:0',
|
||||
'low_stock_alert' => 'nullable|numeric|min:0',
|
||||
'image' => 'nullable|image',
|
||||
|
||||
// ===== Supplier & Purchase Info =====
|
||||
'supplier_id' => 'nullable|exists:suppliers,id',
|
||||
'last_purchase_price' => 'nullable|numeric|min:0',
|
||||
'last_purchase_date' => 'nullable|date',
|
||||
|
||||
// ===== Units & Conversions =====
|
||||
'conversion_factor' => 'nullable|numeric|min:0.01',
|
||||
|
||||
// ===== Stock & Inventory =====
|
||||
'reserved_quantity' => 'nullable|numeric|min:0',
|
||||
'wastage_quantity' => 'nullable|numeric|min:0',
|
||||
|
||||
// ===== Categorization =====
|
||||
'category' => 'nullable|string|max:100',
|
||||
'notes' => 'nullable|string|max:2000',
|
||||
|
||||
// ===== Status =====
|
||||
'status' => 'nullable|in:0,1',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user