This commit is contained in:
2025-09-25 03:03:31 +05:00
commit ae480cf2f6
2768 changed files with 1485826 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Models\Ecommerce\Product\Order\Concerns;
trait HasPayments
{
/**
* Total price for order
*/
public function total(): float
{
return $this->items->sum('total');
}
/**
* Return total order with shipping.
*/
public function fullPriceWithShipping(): string
{
return floatval($this->total()) + floatval($this->shippingPrice()) + floatval($this->additional_tax);
}
/**
* Formatted payment type
*/
public function formattedPaymentType(): string
{
return $this->paymentType?->name;
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Models\Ecommerce\Product\Order\Concerns;
use App\Models\Ecommerce\Product\Order\Shipping\OrderShipping;
trait HasShipping
{
/**
* Shipping price
*/
public function shippingPrice(): int
{
return intval($this->shipping_price) ?: OrderShipping::priceFor($this->shipping_method);
}
/**
* Formatted shipping method
*/
public function formattedShippingMethod(): string
{
return OrderShipping::formattedShippingMethod($this->shipping_method);
}
/**
* Full address for the order
*/
public function fullAddress(): string
{
return OrderShipping::fullAddress($this->region, $this->province_id, $this->customer_address);
}
}

View File

@@ -0,0 +1,72 @@
<?php
namespace App\Models\Ecommerce\Product\Order\Concerns;
use App\Models\Ecommerce\Product\Order\Status\OrderStatus;
trait HasStatus
{
/**
* Return the correct order status formatted.
*/
public function formatted_status(): string
{
return OrderStatus::formattedStatusFor($this->status);
}
/**
* Can order be cancelled?
*/
public function canBeCancelled(): bool
{
return $this->isPending();
}
/**
* Check if order is pending
*/
public function isPending(): bool
{
return $this->status === OrderStatus::PENDING;
}
/**
* Check if order is registered
*/
public function isRegistered(): bool
{
return $this->status === OrderStatus::REGISTER;
}
/**
* Check if order is paid
*/
public function isPaid(): bool
{
return $this->status === OrderStatus::PAID;
}
/**
* Check if order is completed
*/
public function isCompleted(): bool
{
return $this->status === OrderStatus::COMPLETED;
}
/**
* Check if order is completed
*/
public function isCancelled(): bool
{
return $this->status === OrderStatus::CANCELLED;
}
/**
* Mark order as paid
*/
public function markAsPaid(): void
{
$this->update(['status' => OrderStatus::PAID]);
}
}

View File

@@ -0,0 +1,87 @@
<?php
namespace App\Models\Ecommerce\Product\Order;
use App\Models\Ecommerce\Product\Order\Concerns\HasPayments;
use App\Models\Ecommerce\Product\Order\Concerns\HasShipping;
use App\Models\Ecommerce\Product\Order\Concerns\HasStatus;
use App\Models\System\Settings\Location\Province;
use App\Models\System\Settings\Payments\PaymentType;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
class Order extends Model
{
use HasFactory;
use HasPayments;
use HasShipping;
use HasStatus;
use SoftDeletes;
/**
* The attributes that are mass assignable.
*
* @var array<string>
*/
protected $fillable = [
'number',
'status',
'shipping_method',
'shipping_price',
'payment_type_id',
'notes',
'customer_name',
'customer_phone',
'customer_address',
'delivery_time',
'delivery_at',
'region',
'user_id',
'additional_tax',
'province_id',
'source_app',
];
/**
* The attributes that should be cast.
*/
protected $casts = [
'delivery_at' => 'date',
];
/**
* User (customer)
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* Related Province
*/
public function province(): BelongsTo
{
return $this->belongsTo(Province::class);
}
/**
* Order items
*/
public function items(): HasMany
{
return $this->hasMany(OrderItem::class);
}
/**
* Payment types
*/
public function paymentType(): BelongsTo
{
return $this->belongsTo(PaymentType::class, 'payment_type_id');
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace App\Models\Ecommerce\Product\Order;
use App\Models\Ecommerce\Channel\Channel;
use App\Models\Ecommerce\Product\Product\Product;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class OrderItem extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<string>
*/
protected $fillable = [
'product_name',
'product_id',
'order_id',
'channel_id',
'quantity',
'unit_price_amount',
'unit_cost_amount',
];
/**
* Related order (parent)
*/
public function order(): BelongsTo
{
return $this->belongsTo(Order::class, 'order_id');
}
/**
* Related product
*/
public function product(): BelongsTo
{
return $this->belongsTo(Product::class, 'product_id', 'id');
}
/**
* Related Channel
*/
public function channel(): BelongsTo
{
return $this->belongsTo(Channel::class, 'channel_id', 'id');
}
/**
* Total price
*/
public function total(): Attribute
{
return Attribute::make(
get: fn () => (float) $this->unit_price_amount * (int) $this->quantity
);
}
}

View File

@@ -0,0 +1,88 @@
<?php
namespace App\Models\Ecommerce\Product\Order\Payment;
use App\Models\System\Settings\Payments\PaymentType;
use App\Repositories\System\Cache\CacheRepository;
class OrderPayment
{
/**
* Cash
*/
public const CASH = 'cash';
/**
* ATM
*/
public const ATM = 'atm';
/**
* Online (halkbank)
*/
public const ONLINE = 'online';
/**
* Online (halkbank)
*/
public const HALK_BANK = 'halk_bank';
/**
* Online (senagat)
*/
public const SENAGAT_BANK = 'senegat_bank';
/**
* Online (rysgal)
*/
public const RYSGAL_BANK = 'rysgal_bank';
/**
* Online (wneshka)
*/
public const WNESHKA_BANK = 'wneshka_bank';
/**
* Default payment value
*/
public static function default(): ?string
{
return CacheRepository::make(
name: 'cs-nova-models-default-order-payment',
value: fn () => PaymentType::where('code', 'cash')->pluck('id')->first(),
time: 60 * 60 * 24
);
}
/**
* Payment values
*/
public static function values(): array
{
return CacheRepository::make(
name: 'cs-nova-models-order-payments',
value: fn () => PaymentType::pluck('name', 'id')->toArray()
);
}
/**
* Old but good types
*
* @return array<int, string>
*/
public static function oldButGoodTypes(): array
{
return [
static::ATM => __('ATM'),
static::CASH => __('Cash'),
];
}
/**
* Formatted payment type for given "type"
*/
public static function formattedPaymentTypeFor(string $type): string
{
return static::values()[$type] ?? self::CASH;
}
}

View File

@@ -0,0 +1,201 @@
<?php
namespace App\Models\Ecommerce\Product\Order\Shipping;
use App\Models\Ecommerce\Product\Order\Order;
use App\Models\System\Settings\Location\Province;
use App\Models\System\Settings\Location\Region;
class OrderShipping
{
/*
* Shipping methods
*
* standart - basic
* express - fast
* self_pickup - self pickup
* region - deliver to regions (mr, ah, dz, lb, bn)
*/
/**
* Standart shipping
*/
public const STANDART = 'standart';
/**
* Express shipping
*/
public const EXPRESS = 'express';
/**
* On own - self pickup
*/
public const SELF_PICKUP = 'self_pickup';
/**
* Region - shipping to regions (mr, ah, ...)
*/
public const REGION = 'region';
/*
* Shipping method prices
*
* standart - 20
* express - 30
* self pickup - 0
* region - 40
*/
/**
* Standart shipping price
*/
public const STANDART_PRICE = 20;
/**
* Express shipping price
*/
public const EXPRESS_PRICE = 30;
/**
* Self pickup shipping price
*/
public const SELF_PICKUP_PRICE = 0;
/**
* Region shipping price
*/
public const REGION_PRICE = 40;
/**
* Order delivery times
*
* morning
* evening
*/
/**
* Morning time 09 - 12:00
*/
public const MORNING = '09:00 - 12:00';
/**
* Evening time 13:00 - 18:00
*/
public const EVENING = '13:00 - 18:00';
/**
* Default shipping value
*/
public static function default(): string
{
return static::STANDART;
}
/**
* Default shipping time value
*/
public static function defaultTime(): string
{
return static::EVENING;
}
/**
* Shipping values
*/
public static function values(): array
{
return [
self::STANDART => __('Standart'),
self::EXPRESS => __('Express'),
self::SELF_PICKUP => __('Self Pickup'),
self::REGION => __('Region'),
];
}
/**
* Prices
*/
public static function prices(): array
{
return [
self::STANDART => self::STANDART_PRICE,
self::EXPRESS => self::EXPRESS_PRICE,
self::SELF_PICKUP => self::SELF_PICKUP_PRICE,
self::REGION => self::REGION_PRICE,
];
}
/**
* Shipping times
*/
public static function times(): array
{
return [
self::MORNING => self::MORNING,
self::EVENING => self::EVENING,
];
}
/**
* Get price for specific shipping
*/
public static function priceFor(string $type): int
{
return static::prices()[$type] ?? self::STANDART_PRICE;
}
/**
* Order shipping price
*
* @param Order $order
*/
public static function orderShippingPrice($order): int
{
if ($order->region === Region::AG) {
return static::priceFor($order->shipping_method);
}
if (in_array($order->province_id, [
12,
43,
45,
83,
56,
22,
])) {
return 30;
}
return static::REGION_PRICE;
}
/**
* Formatted shipping method
*/
public static function formattedShippingMethod(string $shippingMethod): string
{
return static::values()[$shippingMethod] ?? __('Standart');
}
/**
* Get full address
*/
public static function fullAddress($region, $province, $customer_address): string
{
$address = '';
if ($region) {
$address .= Region::labelFor($region);
}
if ($province = Province::where('id', $province)->first('name')) {
$address .= ', '.$province->name;
}
if ($customer_address) {
$address .= ','.$customer_address;
}
return $address;
}
}

View File

@@ -0,0 +1,89 @@
<?php
namespace App\Models\Ecommerce\Product\Order\Status;
class OrderStatus
{
/**
* Pending orders are brand new orders that have not been processed yet.
*/
public const PENDING = 'pending';
/**
* Orders that has been registered..
*/
public const REGISTER = 'register';
/**
* Orders that has been paid..
*/
public const PAID = 'paid';
/**
* Orders fulfilled completely.
*/
public const COMPLETED = 'completed';
/**
* Order that has been cancelled.
*/
public const CANCELLED = 'cancelled';
/**
* Default status value
*/
public static function default(): string
{
return static::PENDING;
}
/**
* Status Values
*/
public static function values(): array
{
return [
self::PENDING => __('Pending'),
self::REGISTER => __('Registered'),
self::PAID => __('Paid'),
self::COMPLETED => __('Completed'),
self::CANCELLED => __('Cancelled'),
];
}
/**
* Formatted status for given "status"
*/
public static function formattedStatusFor(string $status): string
{
return static::values()[$status] ?? __('None');
}
/**
* Tailwind
*/
public static function classes(): array
{
return [
self::PENDING => 'warning',
self::REGISTER => 'info',
self::PAID => 'primary',
self::COMPLETED => 'success',
self::CANCELLED => 'danger',
];
}
/**
* HEX Colors
*/
public static function colors(): array
{
return [
self::PENDING => '#F5573B',
self::REGISTER => '#F2CB22',
self::PAID => '#098F56',
self::COMPLETED => '#8FC15D',
self::CANCELLED => '#d70206',
];
}
}