first upload all files
This commit is contained in:
27
Modules/Order/Admin/OrderTable.php
Normal file
27
Modules/Order/Admin/OrderTable.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order\Admin;
|
||||
|
||||
use Modules\Admin\Ui\AdminTable;
|
||||
|
||||
class OrderTable extends AdminTable
|
||||
{
|
||||
/**
|
||||
* Make table response for the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function make()
|
||||
{
|
||||
return $this->newTable()
|
||||
->addColumn('customer_name', function ($order) {
|
||||
return $order->customer_full_name;
|
||||
})
|
||||
->editColumn('total', function ($order) {
|
||||
return $order->total->format();
|
||||
})
|
||||
->editColumn('status', function ($order) {
|
||||
return $order->status();
|
||||
});
|
||||
}
|
||||
}
|
||||
22
Modules/Order/Config/assets.php
Normal file
22
Modules/Order/Config/assets.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Define which assets will be available through the asset manager
|
||||
|--------------------------------------------------------------------------
|
||||
| These assets are registered on the asset manager
|
||||
*/
|
||||
'all_assets' => [
|
||||
'admin.order.css' => ['module' => 'order:admin/css/order.css'],
|
||||
'admin.order.js' => ['module' => 'order:admin/js/order.js'],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Define which default assets will always be included in your pages
|
||||
| through the asset pipeline
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'required_assets' => [],
|
||||
];
|
||||
9
Modules/Order/Config/permissions.php
Normal file
9
Modules/Order/Config/permissions.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'admin.orders' => [
|
||||
'index' => 'order::permissions.index',
|
||||
'show' => 'order::permissions.show',
|
||||
'edit' => 'order::permissions.edit',
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateOrdersTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('orders', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('customer_id')->nullable()->index();
|
||||
$table->string('customer_email');
|
||||
$table->string('customer_phone')->nullable();
|
||||
$table->string('customer_first_name');
|
||||
$table->string('customer_last_name');
|
||||
$table->string('billing_first_name');
|
||||
$table->string('billing_last_name');
|
||||
$table->string('billing_address_1');
|
||||
$table->string('billing_address_2')->nullable();
|
||||
$table->string('billing_city');
|
||||
$table->string('billing_state');
|
||||
$table->string('billing_zip');
|
||||
$table->string('billing_country');
|
||||
$table->string('shipping_first_name');
|
||||
$table->string('shipping_last_name');
|
||||
$table->string('shipping_address_1');
|
||||
$table->string('shipping_address_2')->nullable();
|
||||
$table->string('shipping_city');
|
||||
$table->string('shipping_state');
|
||||
$table->string('shipping_zip');
|
||||
$table->string('shipping_country');
|
||||
$table->decimal('sub_total', 18, 4)->unsigned();
|
||||
$table->string('shipping_method');
|
||||
$table->decimal('shipping_cost', 18, 4)->unsigned();
|
||||
$table->integer('coupon_id')->nullable()->index();
|
||||
$table->decimal('discount', 18, 4)->unsigned();
|
||||
$table->decimal('total', 18, 4)->unsigned();
|
||||
$table->string('payment_method');
|
||||
$table->string('currency');
|
||||
$table->decimal('currency_rate', 18, 4);
|
||||
$table->string('locale');
|
||||
$table->string('status');
|
||||
$table->softDeletes();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('orders');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateOrderProductsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('order_products', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('order_id')->unsigned();
|
||||
$table->integer('product_id')->unsigned();
|
||||
$table->decimal('unit_price', 18, 4)->unsigned();
|
||||
$table->integer('qty');
|
||||
$table->decimal('line_total', 18, 4)->unsigned();
|
||||
|
||||
$table->foreign('order_id')->references('id')->on('orders')->onDelete('cascade');
|
||||
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('order_products');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateOrderProductOptionsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('order_product_options', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('order_product_id')->unsigned();
|
||||
$table->integer('option_id')->unsigned();
|
||||
|
||||
$table->unique(['order_product_id', 'option_id']);
|
||||
$table->foreign('order_product_id')->references('id')->on('order_products')->onDelete('cascade');
|
||||
$table->foreign('option_id')->references('id')->on('options')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('order_product_options');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateOrderProductOptionValuesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('order_product_option_values', function (Blueprint $table) {
|
||||
$table->integer('order_product_option_id')->unsigned();
|
||||
$table->integer('option_value_id')->unsigned();
|
||||
$table->decimal('price', 18, 4)->unsigned()->nullable();
|
||||
|
||||
$table->primary(['order_product_option_id', 'option_value_id'], 'order_product_option_id_option_value_id_primary');
|
||||
$table->foreign('order_product_option_id')->references('id')->on('order_product_options')->onDelete('cascade');
|
||||
$table->foreign('option_value_id')->references('id')->on('option_values')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('order_product_option_values');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateOrderTaxesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('order_taxes', function (Blueprint $table) {
|
||||
$table->integer('order_id')->unsigned();
|
||||
$table->integer('tax_rate_id')->unsigned();
|
||||
$table->decimal('amount', 15, 4)->unsigned();
|
||||
|
||||
$table->primary(['order_id', 'tax_rate_id']);
|
||||
$table->foreign('order_id')->references('id')->on('orders')->onDelete('cascade');
|
||||
$table->foreign('tax_rate_id')->references('id')->on('tax_rates')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('order_taxes');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddValueColumnToOrderProductOptionsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('order_product_options', function (Blueprint $table) {
|
||||
$table->text('value')->nullable()->after('option_id');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('order_product_options', function (Blueprint $table) {
|
||||
$table->dropColumn('value');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddNoteColumnToOrdersTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('orders', function (Blueprint $table) {
|
||||
$table->text('note')->nullable()->after('status');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('orders', function (Blueprint $table) {
|
||||
$table->dropColumn('note');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class ChangeShippingMethodColumnInOrdersTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
DB::statement('ALTER TABLE orders MODIFY shipping_method VARCHAR(191)');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateOrderDownloadsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('order_downloads', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('order_id')->unsigned();
|
||||
$table->integer('file_id')->unsigned();
|
||||
|
||||
$table->foreign('order_id')->references('id')->on('orders')->onDelete('cascade');
|
||||
$table->foreign('file_id')->references('id')->on('files')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('order_downloads');
|
||||
}
|
||||
}
|
||||
289
Modules/Order/Entities/Order.php
Normal file
289
Modules/Order/Entities/Order.php
Normal file
@@ -0,0 +1,289 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order\Entities;
|
||||
|
||||
use Modules\Cart\CartTax;
|
||||
use Modules\Cart\CartItem;
|
||||
use Modules\Support\Money;
|
||||
use Modules\Support\State;
|
||||
use Modules\Support\Country;
|
||||
use Modules\Media\Entities\File;
|
||||
use Modules\Tax\Entities\TaxRate;
|
||||
use Illuminate\Support\Collection;
|
||||
use Modules\Order\OrderCollection;
|
||||
use Modules\Coupon\Entities\Coupon;
|
||||
use Modules\Order\Admin\OrderTable;
|
||||
use Modules\Support\Eloquent\Model;
|
||||
use Modules\Payment\Facades\Gateway;
|
||||
use Modules\Payment\HasTransactionReference;
|
||||
use Modules\Shipping\Facades\ShippingMethod;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Modules\Transaction\Entities\Transaction;
|
||||
|
||||
class Order extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
const CANCELED = 'canceled';
|
||||
const COMPLETED = 'completed';
|
||||
const ON_HOLD = 'on_hold';
|
||||
const PENDING = 'pending';
|
||||
const PENDING_PAYMENT = 'pending_payment';
|
||||
const PROCESSING = 'processing';
|
||||
const REFUNDED = 'refunded';
|
||||
|
||||
/**
|
||||
* The attributes that aren't mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* The attributes that should be mutated to dates.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $dates = ['start_date', 'end_date', 'deleted_at'];
|
||||
|
||||
public static function totalSales()
|
||||
{
|
||||
return Money::inDefaultCurrency(self::withoutCanceledOrders()->sum('total'));
|
||||
}
|
||||
|
||||
public function status()
|
||||
{
|
||||
return trans("order::statuses.{$this->status}");
|
||||
}
|
||||
|
||||
public function hasShippingMethod()
|
||||
{
|
||||
return !is_null($this->shipping_method);
|
||||
}
|
||||
|
||||
public function hasCoupon()
|
||||
{
|
||||
return !is_null($this->coupon);
|
||||
}
|
||||
|
||||
public function totalTax()
|
||||
{
|
||||
$total = 0;
|
||||
|
||||
if ($this->hasTax()) {
|
||||
$this->taxes()
|
||||
->get()
|
||||
->each(function ($tax) use (&$total) {
|
||||
$total += $tax->order_tax->amount->amount();
|
||||
});
|
||||
}
|
||||
|
||||
return Money::inDefaultCurrency($total);
|
||||
}
|
||||
|
||||
public function hasTax()
|
||||
{
|
||||
return $this->taxes->isNotEmpty();
|
||||
}
|
||||
|
||||
public function salesAnalytics()
|
||||
{
|
||||
return $this->normalizeOrders($this->ordersByWeekDay())->mapWithKeys(function ($orders, $weekDay) {
|
||||
return [$weekDay => $this->dataForChart($orders)];
|
||||
});
|
||||
}
|
||||
|
||||
private function ordersByWeekDay()
|
||||
{
|
||||
return self::select('total', 'created_at')
|
||||
->withoutCanceledOrders()
|
||||
->whereBetween('created_at', [now()->startOfWeek(), now()->endOfWeek()])
|
||||
->get()
|
||||
->reduce(function ($ordersByWeekDay, $order) {
|
||||
$ordersByWeekDay[$order->created_at->weekday()][] = $order;
|
||||
|
||||
return $ordersByWeekDay;
|
||||
});
|
||||
}
|
||||
|
||||
private function normalizeOrders($orders)
|
||||
{
|
||||
return Collection::times(7)->map(function ($dayOfWeek) use ($orders) {
|
||||
return new OrderCollection($orders[$dayOfWeek] ?? []);
|
||||
});
|
||||
}
|
||||
|
||||
private function dataForChart(OrderCollection $orders)
|
||||
{
|
||||
return [
|
||||
'total' => $orders->sumTotal(),
|
||||
'total_orders' => $orders->count(),
|
||||
];
|
||||
}
|
||||
|
||||
public function products()
|
||||
{
|
||||
return $this->hasMany(OrderProduct::class);
|
||||
}
|
||||
|
||||
public function downloads()
|
||||
{
|
||||
return $this->hasMany(OrderDownload::class);
|
||||
}
|
||||
|
||||
public function coupon()
|
||||
{
|
||||
return $this->belongsTo(Coupon::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function taxes()
|
||||
{
|
||||
return $this->belongsToMany(TaxRate::class, 'order_taxes')
|
||||
->using(OrderTax::class)
|
||||
->as('order_tax')
|
||||
->withPivot('amount')
|
||||
->withTrashed();
|
||||
}
|
||||
|
||||
public function transaction()
|
||||
{
|
||||
return $this->hasOne(Transaction::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function getSubTotalAttribute($subTotal)
|
||||
{
|
||||
return Money::inDefaultCurrency($subTotal);
|
||||
}
|
||||
|
||||
public function getShippingCostAttribute($shippingCost)
|
||||
{
|
||||
return Money::inDefaultCurrency($shippingCost);
|
||||
}
|
||||
|
||||
public function getDiscountAttribute($discount)
|
||||
{
|
||||
return Money::inDefaultCurrency($discount);
|
||||
}
|
||||
|
||||
public function getTaxAttribute($tax)
|
||||
{
|
||||
return Money::inDefaultCurrency($tax);
|
||||
}
|
||||
|
||||
public function getTotalAttribute($total)
|
||||
{
|
||||
return Money::inDefaultCurrency($total);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order's shipping method.
|
||||
*
|
||||
* @param string $shippingMethod
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getShippingMethodAttribute($shippingMethod)
|
||||
{
|
||||
return ShippingMethod::get($shippingMethod)->label ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order's payment method.
|
||||
*
|
||||
* @param string $paymentMethod
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPaymentMethodAttribute($paymentMethod)
|
||||
{
|
||||
return Gateway::get($paymentMethod)->label ?? '';
|
||||
}
|
||||
|
||||
public function getCustomerFullNameAttribute()
|
||||
{
|
||||
return "{$this->customer_first_name} {$this->customer_last_name}";
|
||||
}
|
||||
|
||||
public function getBillingFullNameAttribute()
|
||||
{
|
||||
return "{$this->billing_first_name} {$this->billing_last_name}";
|
||||
}
|
||||
|
||||
public function getShippingFullNameAttribute()
|
||||
{
|
||||
return "{$this->shipping_first_name} {$this->shipping_last_name}";
|
||||
}
|
||||
|
||||
public function getBillingCountryNameAttribute()
|
||||
{
|
||||
return Country::name($this->billing_country);
|
||||
}
|
||||
|
||||
public function getShippingCountryNameAttribute()
|
||||
{
|
||||
return Country::name($this->shipping_country);
|
||||
}
|
||||
|
||||
public function getBillingStateNameAttribute()
|
||||
{
|
||||
return State::name($this->billing_country, $this->billing_state);
|
||||
}
|
||||
|
||||
public function getShippingStateNameAttribute()
|
||||
{
|
||||
return State::name($this->shipping_country, $this->shipping_state);
|
||||
}
|
||||
|
||||
public function scopeWithoutCanceledOrders($query)
|
||||
{
|
||||
return $query->whereNotIn('status', [self::CANCELED, self::REFUNDED]);
|
||||
}
|
||||
|
||||
public function storeProducts(CartItem $cartItem)
|
||||
{
|
||||
$orderProduct = $this->products()->create([
|
||||
'product_id' => $cartItem->product->id,
|
||||
'unit_price' => $cartItem->unitPrice()->amount(),
|
||||
'qty' => $cartItem->qty,
|
||||
'line_total' => $cartItem->total()->amount(),
|
||||
]);
|
||||
|
||||
$orderProduct->storeOptions($cartItem->options);
|
||||
}
|
||||
|
||||
public function storeDownloads(CartItem $cartItem)
|
||||
{
|
||||
$cartItem->product->downloads->each(function (File $file) {
|
||||
$this->downloads()->create(['file_id' => $file->id]);
|
||||
});
|
||||
}
|
||||
|
||||
public function attachTax(CartTax $cartTax)
|
||||
{
|
||||
$this->taxes()->attach($cartTax->id(), ['amount' => $cartTax->amount()->amount()]);
|
||||
}
|
||||
|
||||
public function storeTransaction($response)
|
||||
{
|
||||
if (!$response instanceof HasTransactionReference) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->transaction()->create([
|
||||
'transaction_id' => $response->getTransactionReference(),
|
||||
'payment_method' => $this->attributes['payment_method'],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get table data for the resource
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function table()
|
||||
{
|
||||
$query = $this->newQuery()->select(['id', 'customer_first_name', 'customer_last_name', 'customer_email', 'currency', 'total', 'status', 'created_at']);
|
||||
|
||||
return new OrderTable($query);
|
||||
}
|
||||
}
|
||||
45
Modules/Order/Entities/OrderDownload.php
Normal file
45
Modules/Order/Entities/OrderDownload.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order\Entities;
|
||||
|
||||
use Modules\Media\Entities\File;
|
||||
use Modules\Support\Eloquent\Model;
|
||||
|
||||
class OrderDownload extends Model
|
||||
{
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
/**
|
||||
* The relations to eager load on every query.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $with = ['file'];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['file_id'];
|
||||
|
||||
public function getRealPathAttribute()
|
||||
{
|
||||
return $this->file->realPath();
|
||||
}
|
||||
|
||||
public function getFilenameAttribute()
|
||||
{
|
||||
return $this->file->file_name;
|
||||
}
|
||||
|
||||
public function file()
|
||||
{
|
||||
return $this->belongsTo(File::class);
|
||||
}
|
||||
}
|
||||
112
Modules/Order/Entities/OrderProduct.php
Normal file
112
Modules/Order/Entities/OrderProduct.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order\Entities;
|
||||
|
||||
use Modules\Support\Money;
|
||||
use Modules\Support\Eloquent\Model;
|
||||
use Modules\Product\Entities\Product;
|
||||
|
||||
class OrderProduct extends Model
|
||||
{
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
/**
|
||||
* The relations to eager load on every query.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $with = ['product', 'options'];
|
||||
|
||||
/**
|
||||
* The attributes that aren't mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
public function url()
|
||||
{
|
||||
return route('products.show', ['slug' => $this->product->slug]);
|
||||
}
|
||||
|
||||
public function hasAnyOption()
|
||||
{
|
||||
return $this->options->isNotEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if order product has been deleted.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function trashed()
|
||||
{
|
||||
return $this->product->trashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Store order product's options.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Collection $options
|
||||
* @return void
|
||||
*/
|
||||
public function storeOptions($options)
|
||||
{
|
||||
$options->each(function ($option) {
|
||||
$orderProductOption = $this->options()->create([
|
||||
'order_product_id' => $this->id,
|
||||
'option_id' => $option->id,
|
||||
'value' => $option->isFieldType() ? $option->values->first()->label : null,
|
||||
]);
|
||||
|
||||
$orderProductOption->storeValues($this->product, $option->values);
|
||||
});
|
||||
}
|
||||
|
||||
public function product()
|
||||
{
|
||||
return $this->belongsTo(Product::class)
|
||||
->withoutGlobalScope('active')
|
||||
->withTrashed();
|
||||
}
|
||||
|
||||
public function options()
|
||||
{
|
||||
return $this->hasMany(OrderProductOption::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order product's name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNameAttribute()
|
||||
{
|
||||
return $this->product->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order product's slug.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSlugAttribute()
|
||||
{
|
||||
return $this->product->slug;
|
||||
}
|
||||
|
||||
public function getUnitPriceAttribute($unitPrice)
|
||||
{
|
||||
return Money::inDefaultCurrency($unitPrice);
|
||||
}
|
||||
|
||||
public function getLineTotalAttribute($total)
|
||||
{
|
||||
return Money::inDefaultCurrency($total);
|
||||
}
|
||||
}
|
||||
64
Modules/Order/Entities/OrderProductOption.php
Normal file
64
Modules/Order/Entities/OrderProductOption.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order\Entities;
|
||||
|
||||
use Modules\Option\Entities\Option;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Modules\Option\Entities\OptionValue;
|
||||
|
||||
class OrderProductOption extends Model
|
||||
{
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
/**
|
||||
* The relations to eager load on every query.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $with = ['option', 'values'];
|
||||
|
||||
/**
|
||||
* The attributes that aren't mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
public function option()
|
||||
{
|
||||
return $this->belongsTo(Option::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function values()
|
||||
{
|
||||
return $this->belongsToMany(OptionValue::class, 'order_product_option_values')
|
||||
->using(OrderProductOptionValue::class)
|
||||
->withPivot('price');
|
||||
}
|
||||
|
||||
public function getNameAttribute()
|
||||
{
|
||||
return $this->option->name;
|
||||
}
|
||||
|
||||
public function isFieldType()
|
||||
{
|
||||
return $this->option->isFieldType();
|
||||
}
|
||||
|
||||
public function storeValues($product, $values)
|
||||
{
|
||||
$values = $values->mapWithKeys(function (OptionValue $value) use ($product) {
|
||||
return [$value->id => [
|
||||
'price' => $value->priceForProduct($product)->amount(),
|
||||
]];
|
||||
});
|
||||
|
||||
$this->values()->attach($values->all());
|
||||
}
|
||||
}
|
||||
14
Modules/Order/Entities/OrderProductOptionValue.php
Normal file
14
Modules/Order/Entities/OrderProductOptionValue.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order\Entities;
|
||||
|
||||
use Modules\Support\Money;
|
||||
use Illuminate\Database\Eloquent\Relations\Pivot;
|
||||
|
||||
class OrderProductOptionValue extends Pivot
|
||||
{
|
||||
public function getPriceAttribute($price)
|
||||
{
|
||||
return Money::inDefaultCurrency($price);
|
||||
}
|
||||
}
|
||||
14
Modules/Order/Entities/OrderTax.php
Normal file
14
Modules/Order/Entities/OrderTax.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order\Entities;
|
||||
|
||||
use Modules\Support\Money;
|
||||
use Illuminate\Database\Eloquent\Relations\Pivot;
|
||||
|
||||
class OrderTax extends Pivot
|
||||
{
|
||||
public function getAmountAttribute($amount)
|
||||
{
|
||||
return Money::inDefaultCurrency($amount);
|
||||
}
|
||||
}
|
||||
29
Modules/Order/Events/OrderStatusChanged.php
Normal file
29
Modules/Order/Events/OrderStatusChanged.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order\Events;
|
||||
|
||||
use Modules\Order\Entities\Order;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class OrderStatusChanged
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* The instance of order.
|
||||
*
|
||||
* @var \Modules\Order\Entities\Order
|
||||
*/
|
||||
public $order;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param \Modules\Order\Entities\Order $order
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Order $order)
|
||||
{
|
||||
$this->order = $order;
|
||||
}
|
||||
}
|
||||
39
Modules/Order/Http/Controllers/Admin/OrderController.php
Normal file
39
Modules/Order/Http/Controllers/Admin/OrderController.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order\Http\Controllers\Admin;
|
||||
|
||||
use Modules\Order\Entities\Order;
|
||||
use Modules\Admin\Traits\HasCrudActions;
|
||||
|
||||
class OrderController
|
||||
{
|
||||
use HasCrudActions;
|
||||
|
||||
/**
|
||||
* Model for the resource.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = Order::class;
|
||||
|
||||
/**
|
||||
* The relations to eager load on every query.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $with = ['products', 'coupon', 'taxes'];
|
||||
|
||||
/**
|
||||
* Label of the resource.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $label = 'order::orders.order';
|
||||
|
||||
/**
|
||||
* View path of the resource.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $viewPath = 'order::admin.orders';
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order\Http\Controllers\Admin;
|
||||
|
||||
use Modules\Order\Entities\Order;
|
||||
use Modules\Checkout\Mail\Invoice;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class OrderEmailController
|
||||
{
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Modules\Order\Entities\Order $order
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Order $order)
|
||||
{
|
||||
Mail::to($order->customer_email)
|
||||
->send(new Invoice($order));
|
||||
|
||||
return back()->with('success', trans('order::messages.invoice_sent'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order\Http\Controllers\Admin;
|
||||
|
||||
use Modules\Order\Entities\Order;
|
||||
|
||||
class OrderPrintController
|
||||
{
|
||||
/**
|
||||
* Show the specified resource.
|
||||
*
|
||||
* @param \Modules\Order\Entities\Order $order
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(Order $order)
|
||||
{
|
||||
$order->load('products', 'coupon', 'taxes');
|
||||
|
||||
return view('order::admin.orders.print.show', compact('order'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order\Http\Controllers\Admin;
|
||||
|
||||
use Modules\Order\Entities\Order;
|
||||
use Modules\Order\Entities\OrderProduct;
|
||||
use Modules\Order\Events\OrderStatusChanged;
|
||||
|
||||
class OrderStatusController
|
||||
{
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Modules\Order\Entities\Order $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Order $order)
|
||||
{
|
||||
$this->adjustStock($order);
|
||||
|
||||
$order->update(['status' => request('status')]);
|
||||
|
||||
$message = trans('order::messages.status_updated');
|
||||
|
||||
event(new OrderStatusChanged($order));
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
private function adjustStock(Order $order)
|
||||
{
|
||||
if ($this->canceledOrRefunded(request('status'))) {
|
||||
$this->restoreStock($order);
|
||||
}
|
||||
|
||||
if ($this->canceledOrRefunded($order->status)) {
|
||||
$this->reduceStock($order);
|
||||
}
|
||||
}
|
||||
|
||||
private function canceledOrRefunded($status)
|
||||
{
|
||||
return in_array($status, [Order::CANCELED, Order::REFUNDED]);
|
||||
}
|
||||
|
||||
private function restoreStock(Order $order)
|
||||
{
|
||||
$order->products->each(function (OrderProduct $orderProduct) {
|
||||
if ($orderProduct->product->manage_stock) {
|
||||
$orderProduct->product->increment('qty', $orderProduct->qty);
|
||||
}
|
||||
|
||||
if ($orderProduct->product->qty > 0) {
|
||||
$orderProduct->product->markAsInStock();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private function reduceStock(Order $order)
|
||||
{
|
||||
$order->products->each(function (OrderProduct $orderProduct) {
|
||||
if (
|
||||
$orderProduct->product->manage_stock
|
||||
&& $orderProduct->product->qty !== 0
|
||||
) {
|
||||
$orderProduct->product->decrement('qty', $orderProduct->qty);
|
||||
}
|
||||
|
||||
if ($orderProduct->product->qty === 0) {
|
||||
$orderProduct->product->markAsOutOfStock();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
26
Modules/Order/Http/Controllers/OrderController.php
Normal file
26
Modules/Order/Http/Controllers/OrderController.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order\Http\Controllers;
|
||||
|
||||
class OrderController
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('order::index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the specified resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show()
|
||||
{
|
||||
return view('order::show');
|
||||
}
|
||||
}
|
||||
55
Modules/Order/Http/Requests/StoreOrderRequest.php
Normal file
55
Modules/Order/Http/Requests/StoreOrderRequest.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order\Http\Requests;
|
||||
|
||||
use Modules\Support\Country;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Modules\Payment\Facades\Gateway;
|
||||
use Modules\Core\Http\Requests\Request;
|
||||
|
||||
class StoreOrderRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Available attributes.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $availableAttributes = 'checkout::attributes';
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'customer_email' => ['required', 'email', $this->emailUniqueRule()],
|
||||
'customer_phone' => ['required'],
|
||||
'billing.first_name' => 'required',
|
||||
'billing.last_name' => 'required',
|
||||
'billing.address_1' => 'required',
|
||||
'billing.city' => 'required',
|
||||
'billing.zip' => 'required',
|
||||
'billing.country' => ['required', Rule::in(Country::supportedCodes())],
|
||||
'billing.state' => 'required',
|
||||
'create_an_account' => 'boolean',
|
||||
'password' => 'required_if:create_an_account,1',
|
||||
'ship_to_a_different_address' => 'boolean',
|
||||
'shipping.first_name' => 'required_if:ship_to_a_different_address,1',
|
||||
'shipping.last_name' => 'required_if:ship_to_a_different_address,1',
|
||||
'shipping.address_1' => 'required_if:ship_to_a_different_address,1',
|
||||
'shipping.city' => 'required_if:ship_to_a_different_address,1',
|
||||
'shipping.zip' => 'required_if:ship_to_a_different_address,1',
|
||||
'shipping.country' => ['required_if:ship_to_a_different_address,1', Rule::in(Country::supportedCodes())],
|
||||
'shipping.state' => 'required_if:ship_to_a_different_address,1',
|
||||
'payment_method' => ['required', Rule::in(Gateway::names())],
|
||||
'terms_and_conditions' => 'accepted',
|
||||
];
|
||||
}
|
||||
|
||||
private function emailUniqueRule()
|
||||
{
|
||||
return $this->create_an_account ? Rule::unique('users', 'email') : null;
|
||||
}
|
||||
}
|
||||
26
Modules/Order/Listeners/SendOrderStatusChangedEmail.php
Normal file
26
Modules/Order/Listeners/SendOrderStatusChangedEmail.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order\Listeners;
|
||||
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Modules\Order\Events\OrderStatusChanged;
|
||||
use Modules\Order\Mail\OrderStatusChanged as OrderStatusChangedEmail;
|
||||
|
||||
class SendOrderStatusChangedEmail
|
||||
{
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param \Modules\Order\Events\OrderStatusChanged $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(OrderStatusChanged $event)
|
||||
{
|
||||
if (! in_array($event->order->status, setting('email_order_statuses', []))) {
|
||||
return;
|
||||
}
|
||||
|
||||
Mail::to($event->order->customer_email)
|
||||
->send(new OrderStatusChangedEmail($event->order));
|
||||
}
|
||||
}
|
||||
37
Modules/Order/Listeners/SendOrderStatusChangedSms.php
Normal file
37
Modules/Order/Listeners/SendOrderStatusChangedSms.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order\Listeners;
|
||||
|
||||
use Modules\Sms\Sms;
|
||||
use Modules\Order\Entities\Order;
|
||||
use Modules\Order\Events\OrderStatusChanged;
|
||||
|
||||
class SendOrderStatusChangedSms
|
||||
{
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param \Modules\Order\Events\OrderStatusChanged $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(OrderStatusChanged $event)
|
||||
{
|
||||
if (! in_array($event->order->status, setting('sms_order_statuses', []))) {
|
||||
return;
|
||||
}
|
||||
|
||||
Sms::send(
|
||||
$event->order->customer_phone,
|
||||
$this->message($event->order)
|
||||
);
|
||||
}
|
||||
|
||||
private function message(Order $order)
|
||||
{
|
||||
return trans('sms::messages.order_status_changed', [
|
||||
'first_name' => $order->customer_first_name,
|
||||
'order_id' => $order->id,
|
||||
'status' => mb_strtolower($order->status()),
|
||||
]);
|
||||
}
|
||||
}
|
||||
62
Modules/Order/Mail/OrderStatusChanged.php
Normal file
62
Modules/Order/Mail/OrderStatusChanged.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Modules\Media\Entities\File;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
|
||||
class OrderStatusChanged extends Mailable implements ShouldQueue
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
public $heading;
|
||||
public $text;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @param \Modules\Order\Entities\Order $order
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($order)
|
||||
{
|
||||
app()->setLocale($order->locale);
|
||||
|
||||
$this->heading = $this->getHeading($order);
|
||||
$this->text = $this->getText($order);
|
||||
}
|
||||
|
||||
public function getHeading($order)
|
||||
{
|
||||
return trans('storefront::mail.hello', ['name' => $order->customer_first_name]);
|
||||
}
|
||||
|
||||
public function getText($order)
|
||||
{
|
||||
return trans('order::mail.your_order_status_changed_text', [
|
||||
'order_id' => $order->id,
|
||||
'status' => mb_strtolower($order->status()),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
return $this->subject(trans('order::mail.your_order_status_changed_subject'))
|
||||
->view("emails.{$this->getViewName()}", [
|
||||
'logo' => File::findOrNew(setting('storefront_mail_logo'))->path,
|
||||
]);
|
||||
}
|
||||
|
||||
private function getViewName()
|
||||
{
|
||||
return 'text' . (is_rtl() ? '_rtl' : '');
|
||||
}
|
||||
}
|
||||
19
Modules/Order/OrderCollection.php
Normal file
19
Modules/Order/OrderCollection.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order;
|
||||
|
||||
use Modules\Support\Money;
|
||||
use Modules\Order\Entities\Order;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class OrderCollection extends Collection
|
||||
{
|
||||
public function sumTotal()
|
||||
{
|
||||
$total = $this->sum(function (Order $order) {
|
||||
return $order->total->amount();
|
||||
});
|
||||
|
||||
return Money::inDefaultCurrency($total);
|
||||
}
|
||||
}
|
||||
20
Modules/Order/Providers/EventServiceProvider.php
Normal file
20
Modules/Order/Providers/EventServiceProvider.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order\Providers;
|
||||
|
||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||
|
||||
class EventServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* The event listener mappings for the application.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $listen = [
|
||||
\Modules\Order\Events\OrderStatusChanged::class => [
|
||||
\Modules\Order\Listeners\SendOrderStatusChangedEmail::class,
|
||||
\Modules\Order\Listeners\SendOrderStatusChangedSms::class,
|
||||
],
|
||||
];
|
||||
}
|
||||
21
Modules/Order/Providers/OrderServiceProvider.php
Normal file
21
Modules/Order/Providers/OrderServiceProvider.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order\Providers;
|
||||
|
||||
use Modules\Support\Traits\AddsAsset;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class OrderServiceProvider extends ServiceProvider
|
||||
{
|
||||
use AddsAsset;
|
||||
|
||||
/**
|
||||
* Bootstrap the application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
$this->addAdminAssets('admin.orders.show', ['admin.order.css', 'admin.order.js']);
|
||||
}
|
||||
}
|
||||
13
Modules/Order/Resources/assets/admin/js/main.js
Normal file
13
Modules/Order/Resources/assets/admin/js/main.js
Normal file
@@ -0,0 +1,13 @@
|
||||
$('#order-status').change((e) => {
|
||||
$.ajax({
|
||||
type: 'PUT',
|
||||
url: route('admin.orders.status.update', e.currentTarget.dataset.id),
|
||||
data: { status: e.currentTarget.value },
|
||||
success: (message) => {
|
||||
success(message);
|
||||
},
|
||||
error: (xhr) => {
|
||||
error(xhr.responseJSON.message);
|
||||
},
|
||||
});
|
||||
});
|
||||
230
Modules/Order/Resources/assets/admin/sass/main.scss
Normal file
230
Modules/Order/Resources/assets/admin/sass/main.scss
Normal file
@@ -0,0 +1,230 @@
|
||||
.order-information-wrapper,
|
||||
.address-information-wrapper {
|
||||
position: relative;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.order-information-wrapper {
|
||||
.order-information-buttons {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
||||
> a {
|
||||
float: right;
|
||||
padding: 6px 15px;
|
||||
color: #626060;
|
||||
|
||||
& + .tooltip .tooltip-inner {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
> form {
|
||||
float: right;
|
||||
margin-right: 5px;
|
||||
|
||||
button {
|
||||
padding: 6px 12px;
|
||||
color: #626060;
|
||||
|
||||
& + .tooltip .tooltip-inner {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.order-wrapper {
|
||||
background: #ffffff;
|
||||
padding: 15px;
|
||||
border-radius: 3px;
|
||||
|
||||
.order {
|
||||
td .row {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.table {
|
||||
margin: 0;
|
||||
|
||||
> tbody > tr > td {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-weight: 500;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.handling-information span {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.items-ordered {
|
||||
.table-responsive {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.table {
|
||||
border-bottom: 1px solid #e9e9e9;
|
||||
}
|
||||
|
||||
tr {
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
> td {
|
||||
font-size: 16px;
|
||||
padding-top: 16px;
|
||||
padding-bottom: 16px;
|
||||
border-top: 1px solid #f1f1f1 !important;
|
||||
vertical-align: middle;
|
||||
|
||||
&:first-child {
|
||||
min-width: 250px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
color: #444444;
|
||||
letter-spacing: 0.2px;
|
||||
transition: 200ms ease-in-out;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #0068e1;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 14px;
|
||||
display: block;
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
color: #9a9a9a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-group {
|
||||
overflow: hidden;
|
||||
|
||||
> label {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.section-title {
|
||||
border-bottom: 1px solid #d2d6de;
|
||||
padding-bottom: 8px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.order .table-responsive,
|
||||
.account-information .table-responsive {
|
||||
margin-left: -8px;
|
||||
|
||||
tr > td:first-child {
|
||||
font-family: "Open Sans", sans-serif;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.billing-address span,
|
||||
.shipping-address span {
|
||||
line-height: 26px;
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.order-total {
|
||||
textarea {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.order-totals {
|
||||
width: 300px;
|
||||
margin: 15px 15px 0 0;
|
||||
|
||||
tbody > tr {
|
||||
> td {
|
||||
font-family: "Roboto", sans-serif !important;
|
||||
font-weight: 400 !important;
|
||||
font-size: 17px;
|
||||
padding: 5px 8px;
|
||||
}
|
||||
|
||||
&:last-child > td {
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-weight: 500 !important;
|
||||
border-top: 1px solid #e9e9e9;
|
||||
}
|
||||
}
|
||||
|
||||
.coupon-code {
|
||||
font-family: "Open Sans", sans-serif;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 991px) {
|
||||
.order-wrapper {
|
||||
.account-information,
|
||||
.shipping-address,
|
||||
.handling-information {
|
||||
margin-top: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
.order-wrapper {
|
||||
.table {
|
||||
> tbody > tr > td {
|
||||
white-space: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 520px) {
|
||||
.order-information-wrapper {
|
||||
.order-information-buttons {
|
||||
position: relative;
|
||||
top: auto;
|
||||
right: auto;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 400px) {
|
||||
.order-wrapper {
|
||||
.order-totals {
|
||||
width: 250px;
|
||||
}
|
||||
}
|
||||
}
|
||||
698
Modules/Order/Resources/assets/admin/sass/print.scss
Normal file
698
Modules/Order/Resources/assets/admin/sass/print.scss
Normal file
@@ -0,0 +1,698 @@
|
||||
html {
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-print-color-adjust: exact;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
font-size: 15px;
|
||||
min-width: 350px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6, ul, li, p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #444444;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 36px;
|
||||
line-height: 44px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 30px;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
line-height: 29px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 21px;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 18px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
td, th {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
* {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:before, &:after {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.container {
|
||||
width: 750px;
|
||||
}
|
||||
|
||||
.col-sm-6 {
|
||||
float: left;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.rtl .col-sm-6 {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.container {
|
||||
width: 970px;
|
||||
}
|
||||
|
||||
.col-md-3,
|
||||
.col-md-9 {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.rtl .col-md-3,
|
||||
.rtl .col-md-9 {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.col-md-12 {
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.rtl .col-md-12 {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.col-md-9 {
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
.col-md-3 {
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.container {
|
||||
width: 1170px;
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-left: -15px;
|
||||
margin-right: -15px;
|
||||
}
|
||||
|
||||
.col-md-3,
|
||||
.col-sm-6,
|
||||
.col-md-9,
|
||||
.col-md-12 {
|
||||
position: relative;
|
||||
min-height: 1px;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.rtl th {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.table {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
margin-bottom: 20px;
|
||||
|
||||
> {
|
||||
thead > tr > th,
|
||||
tbody > tr > th,
|
||||
tfoot > tr > th,
|
||||
thead > tr > td,
|
||||
tbody > tr > td,
|
||||
tfoot > tr > td {
|
||||
padding: 8px;
|
||||
line-height: 1.42857143;
|
||||
vertical-align: top;
|
||||
border-top: 1px solid #dddddd;
|
||||
}
|
||||
|
||||
thead > tr > th {
|
||||
vertical-align: bottom;
|
||||
border-bottom: 2px solid #dddddd;
|
||||
}
|
||||
|
||||
caption + thead > tr:first-child > th,
|
||||
colgroup + thead > tr:first-child > th,
|
||||
thead:first-child > tr:first-child > th,
|
||||
caption + thead > tr:first-child > td,
|
||||
colgroup + thead > tr:first-child > td,
|
||||
thead:first-child > tr:first-child > td {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
tbody + tbody {
|
||||
border-top: 2px solid #dddddd;
|
||||
}
|
||||
}
|
||||
|
||||
.table {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
col[class*="col-"] {
|
||||
position: static;
|
||||
float: none;
|
||||
display: table-column;
|
||||
}
|
||||
|
||||
td[class*="col-"],
|
||||
th[class*="col-"] {
|
||||
position: static;
|
||||
float: none;
|
||||
display: table-cell;
|
||||
}
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
overflow-x: auto;
|
||||
min-height: 0.01%;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
.table-responsive {
|
||||
width: 100%;
|
||||
overflow-y: hidden;
|
||||
-ms-overflow-style: -ms-autohiding-scrollbar;
|
||||
|
||||
> .table {
|
||||
margin-bottom: 0;
|
||||
|
||||
> {
|
||||
thead > tr > th,
|
||||
tbody > tr > th,
|
||||
tfoot > tr > th,
|
||||
thead > tr > td,
|
||||
tbody > tr > td,
|
||||
tfoot > tr > td {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.clearfix {
|
||||
&:before,
|
||||
&:after {
|
||||
content: "";
|
||||
display: table;
|
||||
}
|
||||
}
|
||||
.container {
|
||||
&:before,
|
||||
&:after {
|
||||
content: "";
|
||||
display: table;
|
||||
}
|
||||
}
|
||||
.container-fluid {
|
||||
&:before,
|
||||
&:after {
|
||||
content: "";
|
||||
display: table;
|
||||
}
|
||||
}
|
||||
.row {
|
||||
&:before,
|
||||
&:after {
|
||||
content: "";
|
||||
display: table;
|
||||
}
|
||||
}
|
||||
|
||||
.clearfix:after,
|
||||
.container:after,
|
||||
.container-fluid:after,
|
||||
.row:after {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.pull-right {
|
||||
float: right !important;
|
||||
}
|
||||
|
||||
.rtl .pull-right {
|
||||
float: left !important;
|
||||
}
|
||||
|
||||
.pull-left {
|
||||
float: left !important;
|
||||
}
|
||||
|
||||
.rtl .pull-left {
|
||||
float: right !important;
|
||||
}
|
||||
|
||||
.rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.invoice-wrapper {
|
||||
position: relative;
|
||||
padding-bottom: 40px;
|
||||
|
||||
.invoice-header {
|
||||
margin-top: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.invoice-header {
|
||||
.store-name {
|
||||
height: 128px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 60px;
|
||||
font-weight: 600;
|
||||
display: block;
|
||||
color: #444444;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.invoice-info {
|
||||
margin-left: 4px;
|
||||
|
||||
label {
|
||||
color: #444444;
|
||||
}
|
||||
|
||||
span {
|
||||
font-weight: 400;
|
||||
font-size: 15px;
|
||||
float: right;
|
||||
color: #444444;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rtl {
|
||||
.invoice-header {
|
||||
.invoice-info {
|
||||
margin-left: 0;
|
||||
margin-right: 4px;
|
||||
|
||||
span {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.invoice-body .invoice-details {
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.invoice-details h5,
|
||||
.invoice-address h5 {
|
||||
font-weight: 600;
|
||||
color: #444444;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.invoice-details {
|
||||
.table-responsive {
|
||||
overflow: hidden;
|
||||
margin: 0 -8px;
|
||||
}
|
||||
|
||||
.table {
|
||||
margin-bottom: 0;
|
||||
|
||||
td {
|
||||
font-size: 15px;
|
||||
color: #444444;
|
||||
border: none;
|
||||
padding: 4px 8px;
|
||||
|
||||
&:first-child {
|
||||
font-weight: 600;
|
||||
color: #555555;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.invoice-body .invoice-address {
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.invoice-address > span {
|
||||
font-size: 15px;
|
||||
display: block;
|
||||
color: #444444;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.cart-list {
|
||||
border: none;
|
||||
margin-top: 40px;
|
||||
|
||||
.table {
|
||||
margin: 0;
|
||||
border-bottom: 1px solid #e9e9e9;
|
||||
}
|
||||
|
||||
thead tr th {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
color: #444444;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
border-bottom: 1px solid #e9e9e9;
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
padding: 0 15px;
|
||||
|
||||
td {
|
||||
border-top: 1px solid #f1f1f1;
|
||||
color: #444444;
|
||||
padding: 16px 0 18px;
|
||||
vertical-align: middle;
|
||||
|
||||
&:nth-child(4) span {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.option {
|
||||
margin-top: 5px;
|
||||
white-space: nowrap;
|
||||
|
||||
span {
|
||||
font-size: 14px;
|
||||
display: block;
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
margin-left: 2px;
|
||||
color: #9a9a9a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rtl {
|
||||
.cart-list {
|
||||
.option {
|
||||
span {
|
||||
span {
|
||||
margin-left: 0;
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.invoice-body .total {
|
||||
width: 300px;
|
||||
margin: 20px 15px 0 0;
|
||||
|
||||
.table {
|
||||
margin-bottom: 0;
|
||||
|
||||
tr:last-child {
|
||||
border-top: 1px solid #e9e9e9;
|
||||
}
|
||||
|
||||
td {
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
color: #444444;
|
||||
padding: 6px 0;
|
||||
|
||||
&:last-child {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
tr:last-child td {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.coupon-code {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rtl .invoice-body .total {
|
||||
margin: 20px 0 0 15px;
|
||||
|
||||
.table {
|
||||
td:last-child {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 991px) {
|
||||
.invoice-header {
|
||||
.store-name {
|
||||
height: auto;
|
||||
|
||||
h1 {
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.invoice-header-right {
|
||||
float: none !important;
|
||||
margin: auto;
|
||||
display: table;
|
||||
}
|
||||
|
||||
.invoice-info {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.invoice-body .cart-list {
|
||||
margin-top: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
.cart-list {
|
||||
.table-responsive td {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.table {
|
||||
border-top: 1px solid #e9e9e9;
|
||||
}
|
||||
|
||||
thead {
|
||||
display: none;
|
||||
}
|
||||
|
||||
tr {
|
||||
border-bottom: 1px solid #f1f1f1;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
tbody td {
|
||||
&:nth-child(1) {
|
||||
display: block;
|
||||
padding: 15px 0 5px 0;
|
||||
|
||||
> span {
|
||||
font-size: 17px;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(2),
|
||||
&:nth-child(3) {
|
||||
display: block;
|
||||
padding: 0 0 5px 0;
|
||||
}
|
||||
|
||||
&:nth-child(4) {
|
||||
display: block;
|
||||
padding: 0 0 15px 0;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 15px;
|
||||
|
||||
+ span {
|
||||
font-size: 15px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rtl .cart-list {
|
||||
tbody td {
|
||||
label {
|
||||
+ span {
|
||||
margin-left: 0;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.visible-xs {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 530px) {
|
||||
.invoice-wrapper {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
.invoice-wrapper .invoice-header {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.invoice-header {
|
||||
.col-md-3 {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.col-md-9 {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.invoice-header-right {
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.rtl {
|
||||
.invoice-header {
|
||||
.invoice-header-right {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rtl {
|
||||
.invoice-header {
|
||||
.col-md-3 {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.col-md-9 {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.invoice-wrapper .invoice-header-right {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.rtl {
|
||||
.invoice-wrapper .invoice-header-right {
|
||||
margin-right: 0;
|
||||
margin-left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.invoice-details-wrapper .col-md-6 {
|
||||
width: 50%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.rtl {
|
||||
.invoice-details-wrapper .col-md-6 {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.invoice-details .table td:last-child,
|
||||
.invoice-address > span {
|
||||
color: #444444;
|
||||
}
|
||||
|
||||
.invoice-body .cart-list {
|
||||
margin: 30px 0 0;
|
||||
}
|
||||
|
||||
.cart-list .table-responsive tbody td label {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 0;
|
||||
}
|
||||
6
Modules/Order/Resources/lang/en/mail.php
Normal file
6
Modules/Order/Resources/lang/en/mail.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'your_order_status_changed_subject' => 'Your order status is changed',
|
||||
'your_order_status_changed_text' => 'Your order #:order_id status is changed to :status.',
|
||||
];
|
||||
6
Modules/Order/Resources/lang/en/messages.php
Normal file
6
Modules/Order/Resources/lang/en/messages.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'status_updated' => 'Order status has been updated.',
|
||||
'invoice_sent' => 'Invoice has been sent to the customer.',
|
||||
];
|
||||
43
Modules/Order/Resources/lang/en/orders.php
Normal file
43
Modules/Order/Resources/lang/en/orders.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'order' => 'Order',
|
||||
'orders' => 'Orders',
|
||||
'table' => [
|
||||
'customer_name' => 'Customer Name',
|
||||
'customer_email' => 'Customer Email',
|
||||
'total' => 'Total',
|
||||
],
|
||||
'send_email' => 'Send Email',
|
||||
'print' => 'Print',
|
||||
'order_and_account_information' => 'Order & Account Information',
|
||||
'order_information' => 'Order Information',
|
||||
'order_id' => 'Order ID',
|
||||
'order_date' => 'Order Date',
|
||||
'order_status' => 'Order Status',
|
||||
'shipping_method' => 'Shipping Method',
|
||||
'payment_method' => 'Payment Method',
|
||||
'currency' => 'Currency',
|
||||
'currency_rate' => 'Currency Rate',
|
||||
'order_note' => 'Order Note',
|
||||
'account_information' => 'Account Information',
|
||||
'customer_name' => 'Customer Name',
|
||||
'customer_email' => 'Customer Email',
|
||||
'customer_phone' => 'Customer Phone',
|
||||
'customer_group' => 'Customer Group',
|
||||
'guest' => 'Guest',
|
||||
'registered' => 'Registered',
|
||||
'address_information' => 'Address Information',
|
||||
'billing_address' => 'Billing Address',
|
||||
'shipping_address' => 'Shipping Address',
|
||||
'items_ordered' => 'Items Ordered',
|
||||
'product' => 'Product',
|
||||
'unit_price' => 'Unit Price',
|
||||
'quantity' => 'Quantity',
|
||||
'line_total' => 'Line Total',
|
||||
'subtotal' => 'Subtotal',
|
||||
'shipping_method' => 'Shipping Method',
|
||||
'coupon' => 'Coupon',
|
||||
'tax' => 'Tax',
|
||||
'total' => 'Total',
|
||||
];
|
||||
7
Modules/Order/Resources/lang/en/permissions.php
Normal file
7
Modules/Order/Resources/lang/en/permissions.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'index' => 'Index Order',
|
||||
'show' => 'Show Order',
|
||||
'edit' => 'Edit Order',
|
||||
];
|
||||
20
Modules/Order/Resources/lang/en/print.php
Normal file
20
Modules/Order/Resources/lang/en/print.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'invoice' => 'INVOICE',
|
||||
'invoice_id' => 'Invoice ID',
|
||||
'date' => 'Date',
|
||||
'order_details' => 'Order Details',
|
||||
'email' => 'Email',
|
||||
'phone' => 'Phone',
|
||||
'shipping_method' => 'Shipping Method',
|
||||
'payment_method' => 'Payment Method',
|
||||
'billing_address' => 'Billing Address',
|
||||
'shipping_address' => 'Shipping Address',
|
||||
'product' => 'Product',
|
||||
'unit_price' => 'Unit Price',
|
||||
'quantity' => 'Quantity',
|
||||
'line_total' => 'Line Total',
|
||||
'subtotal' => 'Subtotal',
|
||||
'total' => 'Total',
|
||||
];
|
||||
11
Modules/Order/Resources/lang/en/statuses.php
Normal file
11
Modules/Order/Resources/lang/en/statuses.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'canceled' => 'Canceled',
|
||||
'completed' => 'Completed',
|
||||
'on_hold' => 'On Hold',
|
||||
'pending' => 'Pending',
|
||||
'pending_payment' => 'Pending Payment',
|
||||
'processing' => 'Processing',
|
||||
'refunded' => 'Refunded',
|
||||
];
|
||||
46
Modules/Order/Resources/views/admin/orders/index.blade.php
Normal file
46
Modules/Order/Resources/views/admin/orders/index.blade.php
Normal file
@@ -0,0 +1,46 @@
|
||||
@extends('admin::layout')
|
||||
|
||||
@component('admin::components.page.header')
|
||||
@slot('title', trans('order::orders.orders'))
|
||||
|
||||
<li class="active">{{ trans('order::orders.orders') }}</li>
|
||||
@endcomponent
|
||||
|
||||
@section('content')
|
||||
<div class="box box-primary">
|
||||
<div class="box-body index-table" id="orders-table">
|
||||
@component('admin::components.table')
|
||||
@slot('thead')
|
||||
<tr>
|
||||
<th>{{ trans('admin::admin.table.id') }}</th>
|
||||
<th>{{ trans('order::orders.table.customer_name') }}</th>
|
||||
<th>{{ trans('order::orders.table.customer_email') }}</th>
|
||||
<th>{{ trans('admin::admin.table.status') }}</th>
|
||||
<th>{{ trans('order::orders.table.total') }}</th>
|
||||
<th data-sort>{{ trans('admin::admin.table.created') }}</th>
|
||||
</tr>
|
||||
@endslot
|
||||
@endcomponent
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
DataTable.setRoutes('#orders-table .table', {
|
||||
index: '{{ "admin.orders.index" }}',
|
||||
show: '{{ "admin.orders.show" }}',
|
||||
});
|
||||
|
||||
new DataTable('#orders-table .table', {
|
||||
columns: [
|
||||
{ data: 'id', width: '5%' },
|
||||
{ data: 'customer_name', orderable: false, searchable: false },
|
||||
{ data: 'customer_email' },
|
||||
{ data: 'status' },
|
||||
{ data: 'total' },
|
||||
{ data: 'created', name: 'created_at' },
|
||||
],
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,49 @@
|
||||
<div class="address-information-wrapper">
|
||||
<h3 class="section-title">{{ trans('order::orders.address_information') }}</h3>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="billing-address">
|
||||
<h4 class="pull-left">{{ trans('order::orders.billing_address') }}</h4>
|
||||
|
||||
<span>
|
||||
{{ $order->billing_full_name }}
|
||||
<br>
|
||||
{{ $order->billing_address_1 }}
|
||||
<br>
|
||||
|
||||
@if ($order->billing_address_2)
|
||||
{{ $order->billing_address_2 }}
|
||||
<br>
|
||||
@endif
|
||||
|
||||
{{ $order->billing_city }}, {{ $order->billing_state_name }} {{ $order->billing_zip }}
|
||||
<br>
|
||||
{{ $order->billing_country_name }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="shipping-address">
|
||||
<h4 class="pull-left">{{ trans('order::orders.shipping_address') }}</h4>
|
||||
|
||||
<span>
|
||||
{{ $order->shipping_full_name }}
|
||||
<br>
|
||||
{{ $order->shipping_address_1 }}
|
||||
<br>
|
||||
|
||||
@if ($order->shipping_address_2)
|
||||
{{ $order->shipping_address_2 }}
|
||||
<br>
|
||||
@endif
|
||||
|
||||
{{ $order->shipping_city }}, {{ $order->shipping_state_name }} {{ $order->shipping_zip }}
|
||||
<br>
|
||||
{{ $order->shipping_country_name }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,63 @@
|
||||
<div class="items-ordered-wrapper">
|
||||
<h3 class="section-title">{{ trans('order::orders.items_ordered') }}</h3>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="items-ordered">
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ trans('order::orders.product') }}</th>
|
||||
<th>{{ trans('order::orders.unit_price') }}</th>
|
||||
<th>{{ trans('order::orders.quantity') }}</th>
|
||||
<th>{{ trans('order::orders.line_total') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
@foreach ($order->products as $product)
|
||||
<tr>
|
||||
<td>
|
||||
@if ($product->trashed())
|
||||
{{ $product->name }}
|
||||
@else
|
||||
<a href="{{ route('admin.products.edit', $product->product->id) }}">{{ $product->name }}</a>
|
||||
@endif
|
||||
|
||||
@if ($product->hasAnyOption())
|
||||
<br>
|
||||
@foreach ($product->options as $option)
|
||||
<span>
|
||||
{{ $option->name }}:
|
||||
|
||||
<span>
|
||||
@if ($option->option->isFieldType())
|
||||
{{ $option->value }}
|
||||
@else
|
||||
{{ $option->values->implode('label', ', ') }}
|
||||
@endif
|
||||
</span>
|
||||
</span>
|
||||
@endforeach
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ $product->unit_price->format() }}
|
||||
</td>
|
||||
|
||||
<td>{{ $product->qty }}</td>
|
||||
|
||||
<td>
|
||||
{{ $product->line_total->format() }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,132 @@
|
||||
<div class="order-information-wrapper">
|
||||
<div class="order-information-buttons">
|
||||
<a href="{{ route('admin.orders.print.show', $order) }}" class="btn btn-default" target="_blank"
|
||||
data-toggle="tooltip" title="{{ trans('order::orders.print') }}">
|
||||
<i class="fa fa-print" aria-hidden="true"></i>
|
||||
</a>
|
||||
|
||||
<form method="POST" action="{{ route('admin.orders.email.store', $order) }}">
|
||||
{{ csrf_field() }}
|
||||
|
||||
<button type="submit" class="btn btn-default" data-toggle="tooltip"
|
||||
title="{{ trans('order::orders.send_email') }}" data-loading>
|
||||
<i class="fa fa-envelope-o" aria-hidden="true"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<h3 class="section-title">{{ trans('order::orders.order_and_account_information') }}</h3>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="order clearfix">
|
||||
<h4>{{ trans('order::orders.order_information') }}</h4>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ trans('order::orders.order_id') }}</td>
|
||||
<td>{{ $order->id }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ trans('order::orders.order_date') }}</td>
|
||||
<td>{{ $order->created_at->toFormattedDateString() }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>{{ trans('order::orders.order_status') }}</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-lg-9 col-md-10 col-sm-10">
|
||||
<select id="order-status" class="form-control custom-select-black"
|
||||
data-id="{{ $order->id }}">
|
||||
@foreach (trans('order::statuses') as $name => $label)
|
||||
<option value="{{ $name }}"
|
||||
{{ $order->status === $name ? 'selected' : '' }}>
|
||||
{{ $label }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@if ($order->shipping_method)
|
||||
<tr>
|
||||
<td>{{ trans('order::orders.shipping_method') }}</td>
|
||||
<td>{{ $order->shipping_method }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
<tr>
|
||||
<td>{{ trans('order::orders.payment_method') }}</td>
|
||||
<td>{{ $order->payment_method }}
|
||||
@if ($order->payment_method === 'Bank Transfer')
|
||||
</br>
|
||||
{{ setting('bank_transfer_instructions') }}
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@if (is_multilingual())
|
||||
<tr>
|
||||
<td>{{ trans('order::orders.currency') }}</td>
|
||||
<td>{{ $order->currency }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>{{ trans('order::orders.currency_rate') }}</td>
|
||||
<td>{{ $order->currency_rate }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@if ($order->note)
|
||||
<tr>
|
||||
<td>{{ trans('order::orders.order_note') }}</td>
|
||||
<td>{{ $order->note }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="account-information">
|
||||
<h4>{{ trans('order::orders.account_information') }}</h4>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ trans('order::orders.customer_name') }}</td>
|
||||
<td>{{ $order->customer_full_name }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>{{ trans('order::orders.customer_email') }}</td>
|
||||
<td>{{ $order->customer_email }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>{{ trans('order::orders.customer_phone') }}</td>
|
||||
<td>{{ $order->customer_phone }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>{{ trans('order::orders.customer_group') }}</td>
|
||||
|
||||
<td>
|
||||
{{ is_null($order->customer_id) ? trans('order::orders.guest') : trans('order::orders.registered') }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,42 @@
|
||||
<div class="order-totals-wrapper">
|
||||
<div class="row">
|
||||
<div class="order-totals pull-right">
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ trans('order::orders.subtotal') }}</td>
|
||||
<td class="text-right">{{ $order->sub_total->format() }}</td>
|
||||
</tr>
|
||||
|
||||
@if ($order->hasShippingMethod())
|
||||
<tr>
|
||||
<td>{{ $order->shipping_method }}</td>
|
||||
<td class="text-right">{{ $order->shipping_cost->format() }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@foreach ($order->taxes as $tax)
|
||||
<tr>
|
||||
<td>{{ $tax->name }}</td>
|
||||
<td class="text-right">{{ $tax->order_tax->amount->format() }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
@if ($order->hasCoupon())
|
||||
<tr>
|
||||
<td>{{ trans('order::orders.coupon') }} (<span class="coupon-code">{{ $order->coupon->code }}</span>)</td>
|
||||
<td class="text-right">–{{ $order->discount->format() }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
<tr>
|
||||
<td>{{ trans('order::orders.total') }}</td>
|
||||
<td class="text-right">{{ $order->total->format() }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
@push('shortcuts')
|
||||
<dl class="dl-horizontal">
|
||||
<dt><code>b</code></dt>
|
||||
<dd>{{ trans('admin::admin.shortcuts.back_to_index', ['name' => trans('order::orders.order')]) }}</dd>
|
||||
</dl>
|
||||
@endpush
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
keypressAction([
|
||||
{ key: 'b', route: "{{ route('admin.orders.index') }}" }
|
||||
]);
|
||||
</script>
|
||||
@endpush
|
||||
224
Modules/Order/Resources/views/admin/orders/print/show.blade.php
Normal file
224
Modules/Order/Resources/views/admin/orders/print/show.blade.php
Normal file
@@ -0,0 +1,224 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ locale() }}">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<title>{{ trans('order::print.invoice') }}</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,600" rel="stylesheet">
|
||||
<link href="{{ v(Module::asset('order:admin/css/print.css')) }}" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body class="{{ is_rtl() ? 'rtl' : 'ltr' }}">
|
||||
<!--[if lt IE 8]>
|
||||
<p>You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a>
|
||||
to improve your experience.</p>
|
||||
<![endif]-->
|
||||
|
||||
<div class="container">
|
||||
<div class="invoice-wrapper clearfix">
|
||||
<div class="row">
|
||||
<div class="invoice-header clearfix">
|
||||
<div class="col-md-3">
|
||||
<div class="store-name">
|
||||
<h1>{{ setting('store_name') }}</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-9 clearfix">
|
||||
<div class="invoice-header-right pull-right">
|
||||
<span class="title">{{ trans('order::print.invoice') }}</span>
|
||||
|
||||
<div class="invoice-info clearfix">
|
||||
<div class="invoice-id">
|
||||
<label for="invoice-id">{{ trans('order::print.invoice_id') }}:</label>
|
||||
<span>#{{ $order->id }}</span>
|
||||
</div>
|
||||
|
||||
<div class="invoice-date">
|
||||
<label for="invoice-date">{{ trans('order::print.date') }}:</label>
|
||||
<span>{{ $order->created_at->format('Y / m / d') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="invoice-body clearfix">
|
||||
<div class="invoice-details-wrapper">
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-sm-6">
|
||||
<div class="invoice-details">
|
||||
<h5>{{ trans('order::print.order_details') }}</h5>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ trans('order::print.email') }}:</td>
|
||||
<td>{{ $order->customer_email }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>{{ trans('order::print.phone') }}:</td>
|
||||
<td>{{ $order->customer_phone }}</td>
|
||||
</tr>
|
||||
|
||||
@if ($order->shipping_method)
|
||||
<tr>
|
||||
<td>{{ trans('order::print.shipping_method') }}:</td>
|
||||
<td>{{ $order->shipping_method }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
<tr>
|
||||
<td>{{ trans('order::print.payment_method') }}:</td>
|
||||
<td>{{ $order->payment_method }}
|
||||
@if($order->payment_method==='Bank Transfer')
|
||||
</br>
|
||||
{{setting('bank_transfer_instructions')}}
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-sm-6">
|
||||
<div class="invoice-address">
|
||||
<h5>{{ trans('order::print.shipping_address') }}</h5>
|
||||
|
||||
<span>{{ $order->shipping_full_name }}</span>
|
||||
<span>{{ $order->shipping_address_1 }}</span>
|
||||
<span>{{ $order->shipping_address_2 }}</span>
|
||||
<span>{{ $order->shipping_city }}, {{ $order->shipping_state_name }} {{ $order->shipping_zip }}</span>
|
||||
<span>{{ $order->shipping_country_name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 col-sm-6">
|
||||
<div class="invoice-address">
|
||||
<h5>{{ trans('order::print.billing_address') }}</h5>
|
||||
|
||||
<span>{{ $order->billing_full_name }}</span>
|
||||
<span>{{ $order->billing_address_1 }}</span>
|
||||
<span>{{ $order->billing_address_2 }}</span>
|
||||
<span>{{ $order->billing_city }}, {{ $order->billing_state_name }} {{ $order->billing_zip }}</span>
|
||||
<span>{{ $order->billing_country_name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="cart-list">
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ trans('order::print.product') }}</th>
|
||||
<th>{{ trans('order::print.unit_price') }}</th>
|
||||
<th>{{ trans('order::print.quantity') }}</th>
|
||||
<th>{{ trans('order::print.line_total') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($order->products as $product)
|
||||
<tr>
|
||||
<td>
|
||||
<span>{{ $product->name }}</span>
|
||||
|
||||
@if ($product->hasAnyOption())
|
||||
<div class="option">
|
||||
@foreach ($product->options as $option)
|
||||
<span>
|
||||
{{ $option->name }}:
|
||||
|
||||
<span>
|
||||
@if ($option->option->isFieldType())
|
||||
{{ $option->value }}
|
||||
@else
|
||||
{{ $option->values->implode('label', ', ') }}
|
||||
@endif
|
||||
</span>
|
||||
</span>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<label class="visible-xs">{{ trans('order::print.unit_price') }}:</label>
|
||||
<span>{{ $product->unit_price->convert($order->currency, $order->currency_rate)->convert($order->currency, $order->currency_rate)->format($order->currency) }}</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<label class="visible-xs">{{ trans('order::print.quantity') }}:</label>
|
||||
<span>{{ $product->qty }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<label class="visible-xs">{{ trans('order::print.line_total') }}:</label>
|
||||
<span>{{ $product->line_total->convert($order->currency, $order->currency_rate)->format($order->currency) }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="total pull-right">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ trans('order::print.subtotal') }}</td>
|
||||
<td>{{ $order->sub_total->convert($order->currency, $order->currency_rate)->format($order->currency) }}</td>
|
||||
</tr>
|
||||
|
||||
@if ($order->hasShippingMethod())
|
||||
<tr>
|
||||
<td>{{ $order->shipping_method }}</td>
|
||||
<td>{{ $order->shipping_cost->convert($order->currency, $order->currency_rate)->format($order->currency) }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@if ($order->hasCoupon())
|
||||
<tr>
|
||||
<td>{{ trans('order::orders.coupon') }} (<span
|
||||
class="coupon-code">{{ $order->coupon->code }}</span>)
|
||||
</td>
|
||||
<td>
|
||||
–{{ $order->discount->convert($order->currency, $order->currency_rate)->format($order->currency) }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@foreach ($order->taxes as $tax)
|
||||
<tr>
|
||||
<td>{{ $tax->name }}</td>
|
||||
<td class="text-right">{{ $tax->order_tax->amount->convert($order->currency, $order->currency_rate)->format($order->currency) }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
||||
<tr>
|
||||
<td>{{ trans('order::print.total') }}</td>
|
||||
<td>{{ $order->total->convert($order->currency, $order->currency_rate)->format($order->currency) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.print();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
17
Modules/Order/Resources/views/admin/orders/show.blade.php
Normal file
17
Modules/Order/Resources/views/admin/orders/show.blade.php
Normal file
@@ -0,0 +1,17 @@
|
||||
@extends('admin::layout')
|
||||
|
||||
@component('admin::components.page.header')
|
||||
@slot('title', trans('admin::resource.show', ['resource' => trans('order::orders.order')]))
|
||||
|
||||
<li><a href="{{ route('admin.orders.index') }}">{{ trans('order::orders.orders') }}</a></li>
|
||||
<li class="active">{{ trans('admin::resource.show', ['resource' => trans('order::orders.order')]) }}</li>
|
||||
@endcomponent
|
||||
|
||||
@section('content')
|
||||
<div class="order-wrapper">
|
||||
@include('order::admin.orders.partials.order_and_account_information')
|
||||
@include('order::admin.orders.partials.address_information')
|
||||
@include('order::admin.orders.partials.items_ordered')
|
||||
@include('order::admin.orders.partials.order_totals')
|
||||
</div>
|
||||
@endsection
|
||||
33
Modules/Order/Routes/admin.php
Normal file
33
Modules/Order/Routes/admin.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('orders', [
|
||||
'as' => 'admin.orders.index',
|
||||
'uses' => 'OrderController@index',
|
||||
'middleware' => 'can:admin.orders.index',
|
||||
]);
|
||||
|
||||
Route::get('orders/{id}', [
|
||||
'as' => 'admin.orders.show',
|
||||
'uses' => 'OrderController@show',
|
||||
'middleware' => 'can:admin.orders.show',
|
||||
]);
|
||||
|
||||
Route::put('orders/{order}/status', [
|
||||
'as' => 'admin.orders.status.update',
|
||||
'uses' => 'OrderStatusController@update',
|
||||
'middleware' => 'can:admin.orders.edit',
|
||||
]);
|
||||
|
||||
Route::post('orders/{order}/email', [
|
||||
'as' => 'admin.orders.email.store',
|
||||
'uses' => 'OrderEmailController@store',
|
||||
'middleware' => 'can:admin.orders.show',
|
||||
]);
|
||||
|
||||
Route::get('orders/{order}/print', [
|
||||
'as' => 'admin.orders.print.show',
|
||||
'uses' => 'OrderPrintController@show',
|
||||
'middleware' => 'can:admin.orders.show',
|
||||
]);
|
||||
33
Modules/Order/Sidebar/SidebarExtender.php
Normal file
33
Modules/Order/Sidebar/SidebarExtender.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Order\Sidebar;
|
||||
|
||||
use Maatwebsite\Sidebar\Item;
|
||||
use Maatwebsite\Sidebar\Menu;
|
||||
use Maatwebsite\Sidebar\Group;
|
||||
use Modules\Admin\Sidebar\BaseSidebarExtender;
|
||||
|
||||
class SidebarExtender extends BaseSidebarExtender
|
||||
{
|
||||
public function extend(Menu $menu)
|
||||
{
|
||||
$menu->group(trans('admin::sidebar.content'), function (Group $group) {
|
||||
$group->item(trans('admin::sidebar.sales'), function (Item $item) {
|
||||
$item->icon('fa fa-dollar');
|
||||
$item->weight(15);
|
||||
$item->route('admin.orders.index');
|
||||
$item->authorize(
|
||||
$this->auth->hasAnyAccess(['admin.orders.index', 'admin.transactions.index'])
|
||||
);
|
||||
|
||||
$item->item(trans('order::orders.orders'), function (Item $item) {
|
||||
$item->weight(5);
|
||||
$item->route('admin.orders.index');
|
||||
$item->authorize(
|
||||
$this->auth->hasAccess('admin.orders.index')
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
27
Modules/Order/composer.json
Normal file
27
Modules/Order/composer.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "fleetcart/order",
|
||||
"description": "The FleetCart Order Module.",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Envay Soft",
|
||||
"email": "envaysoft@gmail.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.0.2"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Modules\\Order\\": ""
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
},
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
10
Modules/Order/module.json
Normal file
10
Modules/Order/module.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "Order",
|
||||
"alias": "order",
|
||||
"description": "The FleetCart Order Module.",
|
||||
"priority": 100,
|
||||
"providers": [
|
||||
"Modules\\Order\\Providers\\OrderServiceProvider",
|
||||
"Modules\\Order\\Providers\\EventServiceProvider"
|
||||
]
|
||||
}
|
||||
10
Modules/Order/webpack.mix.js
Normal file
10
Modules/Order/webpack.mix.js
Normal file
@@ -0,0 +1,10 @@
|
||||
let mix = require('laravel-mix');
|
||||
let execSync = require('child_process').execSync;
|
||||
|
||||
mix.js(`${__dirname}/Resources/assets/admin/js/main.js`, `${__dirname}/Assets/admin/js/order.js`)
|
||||
.sass(`${__dirname}/Resources/assets/admin/sass/main.scss`, `${__dirname}/Assets/admin/css/order.css`)
|
||||
.sass(`${__dirname}/Resources/assets/admin/sass/print.scss`, `${__dirname}/Assets/admin/css/print.css`)
|
||||
.then(() => {
|
||||
execSync(`npm run rtlcss ${__dirname}/Assets/admin/css/order.css ${__dirname}/Assets/admin/css/order.rtl.css`);
|
||||
execSync(`npm run rtlcss ${__dirname}/Assets/admin/css/print.css ${__dirname}/Assets/admin/css/print.rtl.css`);
|
||||
});
|
||||
Reference in New Issue
Block a user