Compare commits

..

6 Commits

Author SHA1 Message Date
A1Gard 925437ac3c fixed avisa theme part
fixed home links
4 months ago
A1Gard 63b96c1674 added invoice controller
added order relations
fixed ticket bug
4 months ago
A1Gard e9402cac80 optimized ui/ux of menus and customer 4 months ago
A1Gard 9332f1e9d2 optimized ui/ux 4 months ago
A1Gard 21b837759f added persian translate 4 months ago
A1Gard 319a64a748 optimized ux of area designer 4 months ago

@ -77,4 +77,5 @@ SIGN_SMS=true
SIGN_DRIVER=Kavenegar
ZARINPAL_MERCHANT=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
PAY_GATEWAY=zarinpal
ZIBAL_MERCHANT=zibal
PAY_GATEWAY=zibal

@ -315,6 +315,7 @@ function sluger($name, $replace_char = '-')
*/
function lastCrump()
{
$routes = explode('.', Route::currentRouteName());
if (count($routes) != 3) {
echo '<li >

@ -0,0 +1,148 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Controllers\XController;
use App\Http\Requests\InvoiceSaveRequest;
use App\Models\Access;
use App\Models\Credit;
use App\Models\Customer;
use App\Models\Invoice;
use App\Models\Order;
use Illuminate\Http\Request;
use App\Helper;
use function App\Helpers\hasCreateRoute;
class InvoiceController extends XController
{
// protected $_MODEL_ = Invoice::class;
// protected $SAVE_REQUEST = InvoiceSaveRequest::class;
protected $cols = ['hash', 'customer_id', 'count', 'total_price', 'status'];
protected $extra_cols = ['id'];
protected $searchable = ['desc'];
protected $listView = 'admin.invoices.invoice-list';
protected $formView = 'admin.invoices.invoice-form';
protected $buttons = [
'edit' =>
['title' => "Edit", 'class' => 'btn-outline-primary', 'icon' => 'ri-edit-2-line'],
'show' =>
['title' => "Detail", 'class' => 'btn-outline-light', 'icon' => 'ri-eye-line'],
'destroy' =>
['title' => "Remove", 'class' => 'btn-outline-danger delete-confirm', 'icon' => 'ri-close-line'],
];
public function __construct()
{
parent::__construct(Invoice::class, InvoiceSaveRequest::class);
}
/**
* @param $invoice Invoice
* @param $request InvoiceSaveRequest
* @return Invoice
*/
public function save($invoice, $request)
{
$invoice->transport_id = $request->input('transport_id', null);
$invoice->address_id = $request->input('address_id', null);
$invoice->tracking_code = $request->tracking_code;
$invoice->status = $request->status;
$invoice->save();
return $invoice;
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
return view($this->formView);
}
/**
* Show the form for editing the specified resource.
*/
public function edit(Invoice $item)
{
//
return view($this->formView, compact('item'));
}
public function bulk(Request $request)
{
// dd($request->all());
$data = explode('.', $request->input('action'));
$action = $data[0];
$ids = $request->input('id');
switch ($action) {
case 'delete':
$msg = __(':COUNT items deleted successfully', ['COUNT' => count($ids)]);
$this->_MODEL_::destroy($ids);
break;
/**restore*/
case 'restore':
$msg = __(':COUNT items restored successfully', ['COUNT' => count($ids)]);
foreach ($ids as $id) {
$this->_MODEL_::withTrashed()->find($id)->restore();
}
break;
/*restore**/
default:
$msg = __('Unknown bulk action : :ACTION', ["ACTION" => $action]);
}
return $this->do_bulk($msg, $action, $ids);
}
public function destroy(Invoice $item)
{
return parent::delete($item);
}
public function update(Request $request, Invoice $item)
{
return $this->bringUp($request, $item);
}
/**restore*/
public function restore($item)
{
return parent::restoreing(Invoice::withTrashed()->where('id', $item)->first());
}
public function removeOrder(Order $order)
{
$customer = Customer::whereId($order->invoice->customer_id)->first();
if ($order->price_total > 0) {
$diff = $order->price_total;
$customer->credit += $diff;
$customer->save();
$cr = new Credit();
$cr->customer_id = $customer->id;
$cr->amount = $diff;
$cr->data = json_encode([
'user_id' => auth()->user()->id,
'message' => __("Increase by Admin removed:") . ' ' . $order->product->name . __("Invoice") . ' : ' . $order->invoice->hash,
]);
$cr->save();
$order->delete();
}
return redirect()->back()->with('message', __('Order removed successfully'));
}
/*restore**/
}

@ -154,8 +154,8 @@ class CardController extends Controller
$callbackUrl = route('pay.check', ['invoice_hash' => $invoice->hash, 'gateway' => $gateway->getName()]);
$payment = null;
try {
$response = $gateway->request(($invoice->total_price - $invoice->credit_price), $callbackUrl);
$payment = $invoice->storePaymentRequest($response['order_id'], ($invoice->total_price - $invoice->credit_price), $response['token'] ?? null, null, $gateway->getName());
$response = $gateway->request((($invoice->total_price - $invoice->credit_price) * config('app.currency.factor')), $callbackUrl);
$payment = $invoice->storePaymentRequest($response['order_id'], (($invoice->total_price - $invoice->credit_price) * config('app.currency.factor')), $response['token'] ?? null, null, $gateway->getName());
session(["payment_id" => $payment->id]);
\Session::save();
@ -218,7 +218,6 @@ class CardController extends Controller
}
public function productCompareToggle($slug)
{

@ -2,6 +2,7 @@
namespace App\Http\Controllers;
use App\Contracts\Payment;
use App\Http\Requests\ContactSubmitRequest;
use App\Models\Attachment;
use App\Models\Category;
@ -11,6 +12,7 @@ use App\Models\Contact;
use App\Models\Customer;
use App\Models\Gallery;
use App\Models\Group;
use App\Models\Invoice;
use App\Models\Post;
use App\Models\Product;
use App\Models\Quantity;
@ -620,4 +622,42 @@ class ClientController extends Controller
{
return $this->welcome();
}
public function pay($hash){
$invoice = Invoice::where('hash', $hash)->first();
// dd($invoice->created_at->timestamp , (time() - 3600));
if (!in_array($invoice->status, ['PENDING', 'CANCELED', 'FAILED'] ) || $invoice->created_at->timestamp < (time() - 3600) ){
return redirect()->back()->withErrors(__('This payment method is not available.'));
}
$activeGateway = config('xshop.payment.active_gateway');
/** @var Payment $gateway */
$gateway = app($activeGateway . '-gateway');
logger()->info('pay controller', ["active_gateway" => $activeGateway, "invoice" => $invoice->toArray(),]);
if ($invoice->isCompleted()) {
return redirect()->back()->with('message', __('Invoice payed.'));
}
$callbackUrl = route('pay.check', ['invoice_hash' => $invoice->hash, 'gateway' => $gateway->getName()]);
$payment = null;
try {
$response = $gateway->request((($invoice->total_price - $invoice->credit_price) * config('app.currency.factor')), $callbackUrl);
$payment = $invoice->storePaymentRequest($response['order_id'], (($invoice->total_price - $invoice->credit_price) * config('app.currency.factor')), $response['token'] ?? null, null, $gateway->getName());
session(["payment_id" => $payment->id]);
\Session::save();
return $gateway->goToBank();
} catch (\Throwable $exception) {
$invoice->status = 'FAILED';
$invoice->save();
\Log::error("Payment REQUEST exception: " . $exception->getMessage());
\Log::warning($exception->getTraceAsString());
$result = false;
$message = __('error in payment. contact admin.');
return redirect()->back()->withErrors($message);
}
}
}

@ -3,6 +3,7 @@
namespace App\Http\Controllers\Payment;
use App\Contracts\Payment;
use App\Http\Controllers\CardController;
use App\Models\Invoice;
class GatewayVerifyController
@ -31,6 +32,7 @@ class GatewayVerifyController
return redirect()->route('client.card')->withErrors(__("error in payment.").$message);
}
CardController::clear();
return redirect()->route('client.profile')->with('message' , __("payment success"));
}

@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class InvoiceSaveRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'transport_id' => ['nullable', 'integer', 'exists:transports,id'],
'address_id' => ['nullable', 'integer', 'exists:addresses,id'],
'tracking_code' => ['nullable', 'string'],
'status' => ['required', 'string'],
];
}
}

@ -6,10 +6,11 @@ use App\Events\InvoiceFailed;
use App\Events\InvoiceSucceed;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Invoice extends Model
{
use HasFactory;
use HasFactory,SoftDeletes;
const PENDING = 'PENDING';
const PROCESSING = 'PROCESSING';
@ -112,7 +113,7 @@ class Invoice extends Model
$payment->status = "SUCCESS";
$payment->save();
/** @var \App\Models\Invoice $this */
$this->status = "COMPLETED";
$this->status = "PAID";
$this->save();
try {
event(new InvoiceSucceed($this, $payment));

@ -8,4 +8,16 @@ use Illuminate\Database\Eloquent\Model;
class Order extends Model
{
use HasFactory;
public function product(){
return $this->belongsTo(Product::class);
}
public function quantity(){
return $this->belongsTo(Quantity::class);
}
public function invoice(){
return $this->belongsTo(Invoice::class);
}
}

@ -8,7 +8,7 @@ use Illuminate\Database\Eloquent\Model;
class Ticket extends Model
{
// use HasFactory;
public static $ticket_statuses = [['PENDING','ANSWERED','CLOSED']];
public static $ticket_statuses = ['PENDING','ANSWERED','CLOSED'];
public function customer(){

@ -183,6 +183,12 @@ return [
'main' => env('XLANG_MAIN','en'),
'api_url' => env('XLANG_API_URL',''),
],
'xshop' =>[
'payment' => [
'gateway' => env('PAY_GATEWAY',''),
'merchant_id' => env('MERCHANT_ID',''),
]
],

@ -6,11 +6,37 @@
<span v-if="p !== 0" class="btn btn-secondary btn-sm float-end mx-1" @click="shiftArray(p,-1)">
<i class="ri-arrow-up-line"></i>
</span>
<span v-if="p != partsData.length - 1" class="btn btn-secondary btn-sm float-end mx-1" @click="shiftArray(p,1)">
<span v-if="p != partsData.length - 1" class="btn btn-secondary btn-sm float-end mx-1"
@click="shiftArray(p,1)">
<i class="ri-arrow-down-line"></i>
</span>
</div>
<div class="part-body">
<div class="row text-center">
<div class="col">
<button type="button" class="btn btn-secondary mt-4" @click="activeIndex = p">
<i class="ri-edit-2-line"></i>
</button>
</div>
<div class="col-6">
<div class="text-center">
<template v-for="(valid,i) in valids">
<div v-if="valid.data.name == part.part">
<img class="img-fluid" :src="imageLink+'/'+valid.segment+'/'+valid.part"
alt="screeshot">
</div>
</template>
</div>
</div>
<div class="col">
<button type="button" class="btn btn-danger mt-4" @click="rem(p)">
<i class="ri-close-line"></i>
</button>
</div>
</div>
<div v-if="p == activeIndex">
<hr>
<div class="rw">
<template v-for="(valid,i) in valids">
<div @click="changePart(p,valid.segment,valid.part)"
@ -22,10 +48,6 @@
</template>
</div>
</div>
<div class="card-footer">
<button type="button" class="btn btn-danger" @click="rem(p)">
<i class="ri-close-line"></i>
</button>
</div>
<input type="hidden" name="parts[]" :value="JSON.stringify(part)" class="form-control">
</div>
@ -46,6 +68,7 @@ export default {
return {
partsData: [],
removed: [],
activeIndex: null,
}
},
props: {
@ -127,6 +150,7 @@ export default {
.rw {
column-count: 3;
div {
margin-bottom: 1rem;
}

@ -63,6 +63,7 @@
"Addresses": "نشانی‌ها",
"Admin": "مدیر",
"Advertise": "تبلیغ",
"Advs": "تبلیغات",
"Advs list": "فهرست تبلیغات",
"All products": "تمامی محصولات",
"Amount": "میزان",
@ -72,6 +73,7 @@
"Approve": "تایید کردن",
"Approved": "تایید شده",
"Area design": "طراحی محیط",
"Areas": "محیط‌ها ",
"As you wished created successfully": "همانطور که شما مایل بودید ایجاد شد",
"As you wished deattached successfully": "همانطور که شما مایل بودید از پیوست خارج شد",
"As you wished removed successfully": "همانطور که شما مایل بودید حذف شد",
@ -203,6 +205,7 @@
"From - To": "از - تا",
"GFX": "طراحی",
"GFX of website updated": "گرافیک سایت به روز شد",
"Gfxes": "طراحی‌ها",
"Galleries": "گالری‌ها",
"Galleries list": "فهرست گالری‌ها",
"Graphic": "گرافیک",
@ -212,6 +215,7 @@
"Groups": "سرفصل‌ها",
"Groups list": "فهرست سرفصل‌ها",
"Guest": "میهمان",
"Home": "خانه",
"Icon": "نماد",
"If not choose expire expire time will be unlimited": "اگر زمان انقصا را انتخاب نکنید، هرگز منقضی نخواهد شد",
"If you did not receive the email": "اگر ایمیلی دریافت نکردید",
@ -229,6 +233,7 @@
"Invalid area segment": "محیط نامطلوب است",
"Invalid json file!": "فایل جی‌سان معتبر نیست",
"Invalid morph": "چند ریخیتی نا معتبر",
"Invoice payed.": "صورت‌حساب پرداخت شد",
"Invoices": "صورت‌حساب‌ها",
"Is default": "آی پیش‌فرض است",
"Is effective price?": "آیا در قیمت تاثیر دارد؟",
@ -274,10 +279,11 @@
"Orders": "سفارشاات",
"Orders count": "تعداد سفارش",
"Password": "گذرواژه",
"Pay now": "همینک پرداخت کنید",
"Pay now": "پرداخت",
"Payment & discount": "تخفیف و پرداخت",
"Pending": "معلق",
"Pending tickets": "تیکت‌های بی‌پاسخ",
"Phone": "شماره تماس",
"Pin": "سنجاق",
"Please confirm your password before continuing.": "لطفا پیش از ادامه گذرواژه خود را تایید کنید",
"Please upload file": "لطفا یک پرونده بارگزاری کنید",
@ -303,6 +309,7 @@
"Profile": "نمایه",
"Profile updated successfully": "نمایه شما به روز شد",
"Properties meta": "ویژگی‌ها متا",
"Props": "ویژگی‌ها",
"Props list": "فهرست ویژگی‌ها",
"Publish": "منتشر",
"Published": "منتشرشده",
@ -337,15 +344,18 @@
"Save all settings": "ذخیره همه تنظیمات",
"Search": "جستجو",
"Search & Filter": "جستجو و صافی",
"Search for": "جستجو برای",
"Search word is too short": "کلمه مورد جستجو بسیار کوتاه است",
"Searchable": "قابل جستجو",
"Section": "بخش",
"Sections": "بخش‌ها",
"Send": "ارسال",
"Send Answer": "ارسال پاسخ",
"Send Answer and close": "ارسال پاسخ و بستن",
"Send Password Reset Link": "ارسال پیوند بازنشانی گذرواژه",
"Send answer": "",
"Send answer": "ارسال پاسخ",
"Send authenticate code": "ارسال کد احراز هویت",
"Send ticket": "",
"Send ticket": "ارسال تیکت",
"Sent to": "ارسال به",
"Set": "تغییر به",
"Setting": "تنظیمات",
@ -378,6 +388,7 @@
"System notification": "پیام سیستم",
"Tag": "برچسب",
"Tags": "برچسب‌ها",
"Tags list": "فهرست برچسب‌ها",
"Tags, Press enter": "برچسب‌ها، Enter را بزنید",
"The first and\/or second image will be index image": "اولی وی دومی به عنواان تصویر شاخص در نظر گرفته می‌شود",
"Theme": "قالب",
@ -415,6 +426,7 @@
"Upload file": "به روز کردن پرونده",
"Upload images": "بارگزاری تصاویر",
"Upload new images": "بارگزاری تصاویر جدید",
"Use default": "استفاده از پیش فرض ها",
"User filter": "صافی کاربر",
"Users": "کاربران",
"Users list": "فهرست کاربران",
@ -423,14 +435,14 @@
"Video clip": "کلیپ",
"Video clips": "کلیپ‌ها",
"Video clips list": "فهرست کلیپ‌ها",
"View": "",
"View": "تعداد نمایش",
"Visitors": "بازدیدکنندگان",
"Visits": "بازدید‌ها",
"We recommending add title each images": "به شما پیشنهاد می‌کنیم که برای هر تصویر یک عنوان اضافه کنید",
"Website attachments list": "فهرست پیوست‌های سایت",
"Welcome back": "خوش آمدید",
"Width": "عرض",
"You": "",
"You": "شما",
"You are logged in successfully": "شما با موفقیت وارد شدید",
"You can add images after create gallery": "شما می‌توانید بعد از ساختن گالری به آن تصویر اضافه کنید",
"You can add item after create menu": "شما می‌توانید پس از ساختن فهرست به آن آیتم اضافه کنید",
@ -441,6 +453,7 @@
"You don't have access this action": "شما دسترسی لازم برای این بخش را ندارید",
"You don't have any comments, We are so pleased to hear your look-out": "",
"You have some products in your shopping card.": "در سبد خرید شما محصول وجود دارد",
"You must add a pinned post to :GROUP": "برای این قسمت در :GROUP یک نوشته سنجاق شده اضافه کنید",
"You need at least one address to order, Please add address": "شما برای ادامه فرآیند خرید به حداقل یک نشانی نیاز دارید",
"You need complete your information": "شما می‌بایستی اطلاعات خود را تکمیل کنید",
"You need to login first": "شما برای ادامه می‌بایستی وارد شوید",
@ -448,12 +461,15 @@
"You try attempts, Try it a few minutes": "تلاش شما از حداکثر درخواستی بیشتر است",
"You try more than :COUNT attempts, Try it later": "شما بیش از :COUNT تلاش کردید لطفاً بعداً تلاش کنید",
"Your Email sent": "ایمیل شما ارسال شد",
"Your answer ...": "",
"Your answer ...": "پاسخ شما",
"Your comment has been submitted": "دیدگاه شما ارسال شد",
"Your information is insufficient, Please complete your information": "اطلاعات شما ناقص است، لطفا اطلاعات خود را تکمیل کنید",
"Your message ...": "",
"Your message ...": "پیام شما...",
"Your message for this order...": "پیام شما ویژه این سفارش ...",
"Your message has been successfully sent.": "پیام شما با موفقیت ارسال شد",
"Your message...": "پیام شما...",
"a minute ago": "یک دقیقه پیش",
"action": "فعالیت",
"address updated": "نشانی به روز شد",
"an hour ago": "یک ساعت پیش",
"approved": "تایید شد",
@ -461,18 +477,28 @@
"article": "مقاله",
"click here to request another": "برای ایجاد درخواست دیگر اینجا کلیک کنید",
"emoji": "ایموجی",
"email": "رایانامه",
"error in payment.": "خطا در پرداخت",
"error in payment. contact admin.": "خطا در پرداخت با مدیر وبسایت تماس بگیرید",
"image": "تصویر",
"jpg": "",
"minute": "دقیقه",
"minute(s)": "دقیقه",
"name": "نام",
"news": "خبر",
"mobile": "موبایل",
"not searchable": "غیرقابل جستجو",
"one second ago": "یک ثانیه پیش",
"password repeat": "تکرار گذرواژه",
"payment success": "پرداخت موفق بود",
"pending": "معلق",
"rejected": "رد شده",
"sign in": "ورود",
"webp": "",
"xShop": "",
"status": "وضعیت",
"title": "عنوان",
"customer_id": "مشتری",
"user_id": "کاربر",
"yesterday": "دیروز"
}

@ -97,16 +97,23 @@ a.btn,a.action-btn,a.circle-btn{
margin: auto;
border-radius: 3px;
}
.status-0,.status-CLOSED {
.status-0,.status-CLOSED,.status-FAILED,.status-PROCESSING {
background: red;
}
.status-1,.status-ANSWERED{
.status-1,.status-ANSWERED,.status-COMPLETED{
background: lime;
}
.status-PENDING{
background: gold;
}
.status-CANCELED{
background: orange;
}
.status-PAID{
background: white;
}
.image-x64{
height: 64px;

@ -0,0 +1,229 @@
@extends('admin.templates.panel-form-template')
@section('title')
@if(isset($item))
{{__("Edit invoice")}} [{{$item->id}}]
@else
{{__("Add new invoice")}}
@endif -
@endsection
@section('form')
<div class="row">
<div class="col-lg-3">
@include('components.err')
<div class="item-list mb-3">
<h3 class="p-3">
<i class="ri-message-3-line"></i>
{{__("Tips")}}
</h3>
<ul>
<li>
{{__("If you cancel this, You must increase credit yourself.")}}
</li>
<li>
{{__("If you change transport method you must think about think about the price diffrance")}}
</li>
<li>
{{__("If you removed order from invoice, system adding amount to customer's credit automatically")}}
</li>
</ul>
</div>
<div class="item-list mb-3">
<h3 class="p-3">
<i class="ri-user-line"></i>
{{__("Customer")}}
</h3>
<ul>
<li class="mb-2">
<a href="{{route('admin.customer.show',$item->customer->id)}}">
{{__("Name")}}: {{$item->customer->name}}
</a>
</li>
<li class="mb-2">
<a href="{{route('admin.customer.show',$item->customer->id)}}">
{{__("Mobile")}}: {{$item->customer->mobile}}
</a>
</li>
<li class="mb-2">
<a href="{{route('admin.customer.show',$item->customer->id)}}">
{{__("Successfully Invoices")}}
: {{number_format($item->customer->invoices()->whereIn('status',[ 'PAID', 'PROCESSING', 'COMPLETED'])->count())}}
</a>
</li>
<li class="mb-2">
<a href="{{route('admin.customer.show',$item->customer->id)}}">
{{__("Failed Invoices")}}
: {{number_format($item->customer->invoices()->whereIn('status',[ 'PENDING', 'CANCELED', 'FAILED'])->count())}}
</a>
</li>
</ul>
</div>
@if( $item->desc != null && trim($item->desc) != '')
<div class="item-list mb-3">
<h3 class="p-3">
<i class="ri-message-line"></i>
{{__("Description")}}
</h3>
<p class="px-4">
{{$item->desc}}
</p>
</div>
@endif
</div>
<div class="col-lg-9 ps-xl-1 ps-xxl-1">
<div class="general-form ">
<h1>
@if(isset($item))
{{__("Edit invoice")}} [{{$item->id}}]
@else
{{__("Add new invoice")}}
@endif
</h1>
<div class="row">
<div class="col-md-6 mt-3">
<div class="form-group">
<label for="tracking_code">
{{__('Tracking code')}}
</label>
<input name="tracking_code" type="text"
class="form-control @error('tracking_code') is-invalid @enderror" id="tracking_code"
placeholder="{{__('Tracking code')}}" value="{{old('tracking_code',$item->tracking_code??null)}}"/>
</div>
</div>
<div class="col-md-6 mt-3">
<div class="form-group">
<label for="status">
{{__('Status')}}
</label>
<searchable-select
:items='{{arrayNormolizeVueCompatible(\App\Models\Invoice::$invoiceStatus, true)}}'
title-field="name"
value-field="name"
xname="status"
@error('status') :err="true" @enderror
xvalue='{{old('status',$item->status??null)}}'
:close-on-Select="true"></searchable-select>
</div>
</div>
<div class="col-md-12 mt-3">
<h5>
{{__("Address")}}
</h5>
<ul class="list-group">
@foreach($item->customer->addresses as $adr)
<li class="list-group-item">
<label>
<input type="radio" name="address_id" value="{{$adr->id}}"
@if($adr->id == $item->address_id) checked @endif/>
{{$adr->address}}
</label>
</li>
@endforeach
</ul>
</div>
<div class="col-md-12 mt-3">
<h5>
{{__("Address")}}
</h5>
<ul class="list-group">
@foreach(\App\Models\Transport::all() as $t)
<li class="list-group-item">
<label>
<input type="radio" name="transport_id" value="{{$t->id}}"
@if($t->id == $item->transport_id) checked @endif/>
{{$t->title}} ({{number_format($t->price)}})
</label>
</li>
@endforeach
</ul>
</div>
<div class="col-md-12">
<label> &nbsp;</label>
<input name="" type="submit" class="btn btn-primary mt-2" value="{{__('Save')}}"/>
</div>
</div>
</div>
</div>
<div class="mt-4">
<table class="table table-striped align-middle">
<tr>
<th>
#
</th>
<th>
{{__("Product")}}
</th>
<th>
{{__("Count")}}
</th>
<th>
{{__("Quantity")}}
</th>
<th>
{{__("Price")}}
</th>
<th>
-
</th>
</tr>
@foreach($item->orders as $k => $order)
<tr>
<td>
{{$k + 1}}
</td>
<td>
{{$order->product->name}}
</td>
<td>
{{number_format($order->count)}}
</td>
<td>
@if( ($order->quantity->meta??null) == null)
-
@else
@foreach($order->quantity->meta as $m)
<span>
{{$m->human_value}}
</span>
@endforeach
@endif
</td>
<td>
{{number_format($order->price_total)}}
</td>
<td>
<a href="{{route('admin.invoice.remove-order',$order->id)}}" class="btn btn-danger delete-confirm">
<i class="ri-close-circle-line"></i>
</a>
</td>
</tr>
@endforeach
<tr>
<td>
-
</td>
<td>
{{__("Transport")}}
{{number_format($item->transport_price)}}
</td>
<td colspan="2">
{{__("Total price")}}
{{number_format($item->total_price)}}
</td>
<td colspan="2">
{{__("Orders count")}}: ({{number_format($item->count)}})
</td>
</tr>
</table>
</div>
</div>
@endsection

@ -0,0 +1,25 @@
@extends('admin.templates.panel-list-template')
@section('list-title')
<i class="ri-user-3-line"></i>
{{__("Invoices list")}}
@endsection
@section('title')
{{__("Invoices list")}} -
@endsection
@section('filter')
<h2>
<i class="ri-shield-check-line"></i>
{{__("Status")}}:
</h2>
<searchable-multi-select
:items='{{arrayNormolizeVueCompatible(\App\Models\Invoice::$invoiceStatus, true)}}'
title-field="name"
value-field="name"
xname="filter[status]"
:xvalue='{{request()->input('filter.status','[]')}}'
:close-on-Select="true"></searchable-multi-select>
@endsection
@section('bulk')
{{-- <option value="-"> - </option> --}}
@endsection

@ -178,7 +178,10 @@
{{ $item->parent?->{$cols[0]}??'-' }}
@break
@case('status')
<div class="model-status status-{{$item->status}} float-start"></div>
<div class="model-status status-{{$item->status}} float-start" data-bs-toggle="tooltip"
data-bs-placement="top"
data-bs-custom-class="custom-tooltip"
data-bs-title="{{$item->status}}"></div>
@break
@case('user_id')
<a href="{{route('admin.user.edit',$item->user?->email)}}">

@ -8,7 +8,17 @@
{{__("Tickets list")}} -
@endsection
@section('filter')
{{-- Other filters --}}
<h2>
<i class="ri-shield-check-line"></i>
{{__("Status")}}:
</h2>
<searchable-multi-select
:items='{{arrayNormolizeVueCompatible(\App\Models\Ticket::$ticket_statuses, true)}}'
title-field="name"
value-field="name"
xname="filter[status]"
:xvalue='{{request()->input('filter.status','[]')}}'
:close-on-Select="true"></searchable-multi-select>
@endsection
@section('bulk')
<option value="close"> {{__("Close")}} </option>

@ -7,7 +7,7 @@
</a>
</li>
<li>
<a href="{{route('admin.dash')}}">
<a href="{{route('admin.home')}}">
<i class="ri-dashboard-3-line"></i>
{{__("Dashboard")}}
</a>

@ -13,6 +13,14 @@
<i class="ri-shopping-cart-line"></i>
</a>
<ul id="card">
@if( auth()->user()->hasAnyAccess( 'invoice' ))
<li>
<a href="{{ route('admin.invoice.index') }}">
<i class="ri-file-list-3-fill"></i>
{{__('Invoices')}}
</a>
</li>
@endif
@if( auth()->user()->hasAnyAccess( 'customer' ))
<li>
<a href="{{route('admin.customer.index')}}">
@ -22,14 +30,6 @@
</a>
</li>
@endif
@if( auth()->user()->hasAnyAccess( 'invoice' ))
<li>
<a>
<i class="ri-file-list-3-fill"></i>
{{__('Invoices')}}
</a>
</li>
@endif
@if( auth()->user()->hasAnyAccess( 'discount' ))
<li>
<a href="{{route('admin.discount.index')}}">

@ -71,7 +71,7 @@
{{__("Need process orders")}}
</div>
<div class="card-body">
<a href="#">
<a href='{{route('admin.invoice.index')}}?filter%5Bstatus%5D=%5B"PAID"%5D'>
<i class="ri-shopping-bag-4-line"></i>
<h2>
{{number_format(\App\Models\Invoice::where('status','PAID')->count())}}
@ -86,7 +86,7 @@
{{__("Pending tickets")}}
</div>
<div class="card-body">
<a href="{{route('admin.ticket.index')}}">
<a href='{{route('admin.ticket.index')}}?filter%5Bstatus%5D=%5B"PENDING"%5D'>
<i class="ri-customer-service-2-line"></i>
<h2>
{{number_format(\App\Models\Ticket::where('status','PENDING')->count())}}

@ -199,7 +199,7 @@
-
</th>
</tr>
@foreach(auth('customer')->user()->invoices as $inv)
@foreach(auth('customer')->user()->invoices()->orderByDesc('id')->get() as $inv)
<tr>
<td>
{{$inv->hash}}
@ -226,8 +226,8 @@
class="btn btn-outline-primary btn-sm ">
<i class="ri-eye-line"></i>
</a>
@if($inv->status == 'PENDING')
<a href="#" class="btn btn-outline-primary btn-sm ms-2">
@if( in_array($inv->status, ['PENDING', 'CANCELED', 'FAILED'] ) && $inv->created_at->timestamp > (time() - 3600) )
<a href="{{route('client.pay',$inv->hash)}}" class="btn btn-outline-primary btn-sm ms-2">
<i class="ri-secure-payment-line"></i>
{{__("Pay now")}}
</a>
@ -376,7 +376,8 @@
{{__($ticket->status)}}
</td>
<td class="text-center">
<a href="{{ route('client.ticket.show',$ticket->id) }}" class="btn btn-outline-primary btn-sm">
<a href="{{ route('client.ticket.show',$ticket->id) }}"
class="btn btn-outline-primary btn-sm">
<i class="ri-eye-line"></i>
{{__("View")}}
</a>
@ -415,14 +416,16 @@
<label for="title">
{{__("Title")}}
</label>
<input type="text" id="title" name="title" value="{{old('title')}}" placeholder="{{__("Title")}}"
<input type="text" id="title" name="title" value="{{old('title')}}"
placeholder="{{__("Title")}}"
class="form-control">
</div>
<div class="form-group mt-3">
<label for="body">
{{__("Description Text")}}
</label>
<textarea rows="7" name="body" class="form-control" placeholder="{{__("Your message ...")}}">{{old('body')}}</textarea>
<textarea rows="7" name="body" class="form-control"
placeholder="{{__("Your message ...")}}">{{old('body')}}</textarea>
</div>
<div class="mt-3">
<button class="btn btn-outline-primary w-100">
@ -465,9 +468,11 @@
<p class="text-muted">
{{$fav->excerpt}}
</p>
<a class="fav-btn float-end mx-2" data-slug="{{$fav->slug}}" data-is-fav="{{$fav->isFav()}}"
<a class="fav-btn float-end mx-2" data-slug="{{$fav->slug}}"
data-is-fav="{{$fav->isFav()}}"
data-bs-custom-class="custom-tooltip"
data-bs-toggle="tooltip" data-bs-placement="top" title="{{__("Add to / Remove from favorites")}}">
data-bs-toggle="tooltip" data-bs-placement="top"
title="{{__("Add to / Remove from favorites")}}">
<i class="ri-heart-line"></i>
<i class="ri-heart-fill"></i>
</a>

@ -2,6 +2,7 @@ import L from 'leaflet';
var map, marker;
window.addEventListener('load', function () {
try {
// delete L.icon.default.prototype._getIconUrl ;
if (!import.meta.env.DEV) {
@ -30,4 +31,7 @@ window.addEventListener('load',function () {
marker = L.marker({lat: lat, lng: lng}).addTo(map);
}
} catch {
}
});

@ -87,7 +87,7 @@
</a>
</li>
<li class="icon-menu">
<a href="#">
<a href="{{route('client.card')}}">
<i class="ri-shopping-bag-2-line"></i>
<span class="badge bg-danger card-count">
@if(cardCount() > 0)
@ -96,6 +96,19 @@
</span>
</a>
</li>
@if(auth('customer')->check())
<li class="icon-menu">
<a href="{{route('client.profile')}}">
<i class="ri-user-line"></i>
</a>
</li>
@else
<li class="icon-menu">
<a href="{{route('client.sign-in')}}">
<i class="ri-user-line"></i>
</a>
</li>
@endif
<li id="toggler-menu" class="icon-menu">
<a href="#">
<i class="ri-menu-line"></i>

@ -36,6 +36,7 @@
margin: 0 auto;
> li {
flex: 1;
color: white;
text-align: center;
height: 47px;
@ -98,6 +99,10 @@
display: block;
padding: .7rem 0;
}
&.icon-menu{
flex-grow: .4;
}
}
}
@ -150,4 +155,6 @@
~header{
margin-top: 44px;
}
}

@ -13,11 +13,33 @@
</li>
@endforeach
<li class="float-end">
<a href="{{ route('client.card') }}" class="d-inline-block px-1 card-link">
<i class="ri-shopping-bag-2-line"></i>
<span class="badge bg-danger card-count">
@if(cardCount() > 0)
{{cardCount()}}
@endif
</span>
</a>
@if(auth('customer')->check())
<a href="{{route('client.profile')}}" class="d-inline-block px-1 card-link">
<i class="ri-user-line"></i>
</a>
@else
<a href="{{route('client.sign-in')}}" class="d-inline-block px-1 card-link">
<i class="ri-user-line"></i>
</a>
@endif
@if(config('app.xlang.active'))
@foreach(\App\Models\XLang::all() as $lang)
<a href="" class="d-inline-block px-1">
@if($lang->tag != app()->getLocale())
<a href="/{{$lang->tag}}" class="d-inline-block px-1">
{{$lang->emoji}}
</a>
@endif
@endforeach
@endif
</li>
</ul>
</nav>

@ -21,12 +21,20 @@
padding: 1rem;
color: black;
&:hover{
color: var(--xshop-primary);
color: var(--xshop-secondary);
}
}
&:first-child{
display: none;
}
}
}
.card-link{
padding: 5px !important;
margin: 0;
i{
font-size: 22px;
}
}
}

@ -16,7 +16,7 @@ Route::prefix(config('app.panel.prefix'))->name('admin.')->group(
function () {
Route::get('/', [\App\Http\Controllers\HomeController::class, 'index'])->name('dash');
Route::get('/', [\App\Http\Controllers\HomeController::class, 'index'])->name('home');
Route::post('ckeditor/upload', [\App\Http\Controllers\Admin\CkeditorController::class, 'upload'])->name('ckeditor.upload');
Route::get('adminlogs', [\App\Http\Controllers\Admin\AdminLogController::class, 'index'])->name('adminlog.index');
@ -139,6 +139,20 @@ Route::prefix(config('app.panel.prefix'))->name('admin.')->group(
Route::post('sort/save', [\App\Http\Controllers\Admin\CategoryController::class, 'sortSave'])->name('sort-save');
Route::get('sort', [\App\Http\Controllers\Admin\CategoryController::class, 'sort'])->name('sort');
});
Route::prefix('invoices')->name('invoice.')->group(
function () {
Route::get('', [\App\Http\Controllers\Admin\InvoiceController::class, 'index'])->name('index');
// Route::get('create', [\App\Http\Controllers\Admin\InvoiceController::class, 'create'])->name('create');
// Route::post('store', [\App\Http\Controllers\Admin\InvoiceController::class, 'store'])->name('store');
Route::get('edit/{item}', [\App\Http\Controllers\Admin\InvoiceController::class, 'edit'])->name('edit');
Route::get('show/{item}', [\App\Http\Controllers\Admin\InvoiceController::class, 'show'])->name('show');
Route::post('update/{item}', [\App\Http\Controllers\Admin\InvoiceController::class, 'update'])->name('update');
Route::get('delete/{item}', [\App\Http\Controllers\Admin\InvoiceController::class, 'destroy'])->name('destroy');
Route::get('restore/{item}', [\App\Http\Controllers\Admin\InvoiceController::class, 'restore'])->name('restore');
Route::get('remove/ordere/{order}', [\App\Http\Controllers\Admin\InvoiceController::class, 'removeOrder'])->name('remove-order');
Route::post('bulk', [\App\Http\Controllers\Admin\InvoiceController::class, "bulk"])->name('bulk');
Route::get('trashed', [\App\Http\Controllers\Admin\InvoiceController::class, "trashed"])->name('trashed');
});
Route::prefix('posts')->name('post.')->group(
function () {
@ -402,6 +416,7 @@ Route::middleware([\App\Http\Middleware\VisitorCounter::class])
Route::get('/search', [ClientController::class, 'search'])->name('search');
Route::get('attach/download/{attachment}', [ClientController::class, 'attachDl'])->name('attach-dl');
Route::get('/post/{post}', [ClientController::class, 'post'])->name('post');
Route::get('pay/{invoice}', [ClientController::class, 'pay'])->name('pay');
Route::get('product/fav/toggle/{product}', [\App\Http\Controllers\CustomerController::class, 'ProductFavToggle'])->name('product-fav-toggle');
Route::get('product/compare/toggle/{product}', [\App\Http\Controllers\CardController::class, 'productCompareToggle'])->name('product-compare-toggle');
@ -416,8 +431,13 @@ Route::get('/sitemap.xml', [ClientController::class, 'sitemap'])->name('sitemap'
// to developer test
Route::get('login/as/{mobile}', function ($mobile) {
if (auth()->check() && auth()->user()->hasRole('developer')) {
if ($mobile = 1){
return \Auth::guard('customer')
->loginUsingId(\App\Models\Customer::inRandomOrder()->first()->id);
}else{
return \Auth::guard('customer')
->loginUsingId(\App\Models\Customer::where('mobile', $mobile)->first()->id);
}
} else {
return abort(403);
}

Loading…
Cancel
Save