Browse Source

Merge branch 'product_linking' into patch-3

AVMG 3 năm trước cách đây
mục cha
commit
e9bea605c3

+ 32 - 5
app/Http/Controllers/Admin/PaymentController.php

@@ -27,6 +27,7 @@ use PayPalHttp\HttpException;
 
 class PaymentController extends Controller
 {
+
     /**
      * @return Application|Factory|View
      */
@@ -45,7 +46,10 @@ class PaymentController extends Controller
     public function checkOut(Request $request, PaypalProduct $paypalProduct)
     {
         return view('store.checkout')->with([
-            'product' => $paypalProduct
+            'product'      => $paypalProduct,
+            'taxvalue'     => $paypalProduct->getTaxValue(),
+            'taxpercent'   => $paypalProduct->getTaxPercent(),
+            'total'        => $paypalProduct->getTotalPrice()
         ]);
     }
 
@@ -65,8 +69,20 @@ class PaymentController extends Controller
                     "reference_id" => uniqid(),
                     "description" => $paypalProduct->description,
                     "amount"       => [
-                        "value"         => $paypalProduct->price,
-                        "currency_code" => strtoupper($paypalProduct->currency_code)
+                        "value"         => $paypalProduct->getTotalPrice(),
+                        'currency_code' => strtoupper($paypalProduct->currency_code),
+                        'breakdown' =>[
+                            'item_total' =>
+                               [
+                                    'currency_code' => strtoupper($paypalProduct->currency_code),
+                                    'value' => $paypalProduct->price,
+                                ],
+                            'tax_total' =>
+                                [
+                                    'currency_code' => strtoupper($paypalProduct->currency_code),
+                                    'value' => $paypalProduct->getTaxValue(),
+                                ]
+                        ]
                     ]
                 ]
             ],
@@ -76,6 +92,8 @@ class PaymentController extends Controller
                 'brand_name' =>  config('app.name', 'Laravel'),
                 'shipping_preference'  => 'NO_SHIPPING'
             ]
+
+        
         ];
 
 
@@ -161,6 +179,9 @@ class PaymentController extends Controller
                     'status' => $response->result->status,
                     'amount' => $paypalProduct->quantity,
                     'price' => $paypalProduct->price,
+                    'tax_value' => $paypalProduct->getTaxValue(),
+                    'tax_percent' => $paypalProduct->getTaxPercent(),
+                    'total_price' => $paypalProduct->getTotalPrice(),
                     'currency_code' => $paypalProduct->currency_code,
                     'payer' => json_encode($response->result->payer),
                 ]);
@@ -199,7 +220,7 @@ class PaymentController extends Controller
      */
     public function cancel(Request $request)
     {
-        return redirect()->route('store.index')->with('success', 'Payment was Cannceled');
+        return redirect()->route('store.index')->with('success', 'Payment was Canceled');
     }
 
 
@@ -216,7 +237,13 @@ class PaymentController extends Controller
                 return $payment->user->name;
             })
             ->editColumn('price', function (Payment $payment) {
-                return $payment->formatCurrency();
+                return $payment->formatToCurrency($payment->price);
+            })
+            ->editColumn('tax_value', function (Payment $payment) {
+                return $payment->formatToCurrency($payment->tax_value);
+            })
+            ->editColumn('total_price', function (Payment $payment) {
+                return $payment->formatToCurrency($payment->total_price);
             })
             ->editColumn('created_at', function (Payment $payment) {
                 return $payment->created_at ? $payment->created_at->diffForHumans() : '';

+ 1 - 1
app/Http/Controllers/Admin/PaypalProductController.php

@@ -173,7 +173,7 @@ class PaypalProductController extends Controller
                 return $paypalProduct->created_at ? $paypalProduct->created_at->diffForHumans() : '';
             })
             ->editColumn('price', function (PaypalProduct $paypalProduct) {
-                return $paypalProduct->formatCurrency();
+                return $paypalProduct->formatToCurrency($paypalProduct->price);
             })
             ->rawColumns(['actions', 'disabled'])
             ->make();

+ 14 - 8
app/Http/Controllers/ProductController.php

@@ -58,13 +58,13 @@ class ProductController extends Controller
             /** @var Location $location */
             $location = $node->location;
 
-            if (!$locations->contains('id' , $location->id)){
-                $nodeIds = $nodes->map(function ($node){
+            if (!$locations->contains('id', $location->id)) {
+                $nodeIds = $nodes->map(function ($node) {
                     return $node->id;
                 });
 
                 $location->nodes = $location->nodes()
-                    ->whereIn('id' , $nodeIds)
+                    ->whereIn('id', $nodeIds)
                     ->get();
 
                 $locations->add($location);
@@ -76,14 +76,20 @@ class ProductController extends Controller
 
     /**
      * @param Node $node
+     * @param Egg $egg
      * @return Collection|JsonResponse
      */
-    public function getProductsBasedOnNode(Node $node)
+    public function getProductsBasedOnNode(Egg $egg, Node $node)
     {
-        if (is_null($node->id)) return response()->json('Node ID is required', '400');
+        if (is_null($egg->id) || is_null($node->id)) return response()->json('node and egg id is required', '400');
 
-        return Product::query()->whereHas('nodes', function (Builder $builder) use ($node) {
-            $builder->where('id', '=', $node->id);
-        })->get();
+        return Product::query()
+            ->whereHas('nodes', function (Builder $builder) use ($node) {
+                $builder->where('id', '=', $node->id);
+            })
+            ->whereHas('eggs', function (Builder $builder) use ($egg) {
+                $builder->where('id', '=', $egg->id);
+            })
+            ->get();
     }
 }

+ 11 - 2
app/Models/Payment.php

@@ -29,6 +29,9 @@ class Payment extends Model
         'type',
         'amount',
         'price',
+        'tax_value',
+        'total_price',
+        'tax_percent',
         'currency_code',
     ];
 
@@ -51,9 +54,15 @@ class Payment extends Model
         return $this->belongsTo(User::class);
     }
 
-    public function formatCurrency($locale = 'en_US')
+    /**
+     * @param mixed $value
+     * @param string $locale
+     * 
+     * @return float
+     */
+    public function formatToCurrency($value,$locale = 'en_US')
     {
         $formatter = new NumberFormatter($locale, NumberFormatter::CURRENCY);
-        return $formatter->formatCurrency($this->price, $this->currency_code);
+        return $formatter->formatCurrency($value, $this->currency_code);
     }
 }

+ 37 - 3
app/Models/PaypalProduct.php

@@ -6,6 +6,7 @@ use Hidehalo\Nanoid\Client;
 use Illuminate\Database\Eloquent\Model;
 use NumberFormatter;
 use Spatie\Activitylog\Traits\LogsActivity;
+use App\Models\Configuration;
 
 class PaypalProduct extends Model
 {
@@ -40,12 +41,45 @@ class PaypalProduct extends Model
     }
 
     /**
+     * @param mixed $value
      * @param string $locale
-     * @return string
+     * 
+     * @return float
      */
-    public function formatCurrency($locale = 'en_US')
+    public function formatToCurrency($value,$locale = 'en_US')
     {
         $formatter = new NumberFormatter($locale, NumberFormatter::CURRENCY);
-        return $formatter->formatCurrency($this->price, $this->currency_code);
+        return $formatter->formatCurrency($value, $this->currency_code);
+    }
+
+    /**
+    * @description Returns the tax in % taken from the Configuration
+    *
+    * @return int
+    */
+    public function getTaxPercent()
+    {
+        $tax = Configuration::getValueByKey("SALES_TAX");
+        return $tax < 0 ? 0 : $tax;
+    }
+
+    /**
+    * @description Returns the tax as Number
+    *
+    * @return float
+    */
+    public function getTaxValue()
+    {
+        return $this->price*$this->getTaxPercent()/100;
+    }
+
+    /**
+    * @description Returns the full price of a Product including tax
+    *
+    * @return float
+    */
+    public function getTotalPrice() 
+    {
+        return $this->price+($this->getTaxValue());
     }
 }

+ 36 - 0
database/migrations/2021_11_05_071456_add_tax_to_paymentlogs.php

@@ -0,0 +1,36 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class AddTaxToPaymentlogs extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('payments', function (Blueprint $table) {
+            $table->decimal('tax_value',8,2)->after('price')->nullable();
+            $table->integer('tax_percent')->after('tax_value')->nullable();
+            $table->decimal('total_price',8,2)->after('tax_percent')->nullable();    
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('payments', function (Blueprint $table) {
+            $table->dropColumn('tax_value');
+            $table->dropColumn('tax_percent');
+            $table->dropColumn('total_price');
+        });
+    }
+}

+ 8 - 0
database/seeders/Seeds/ConfigurationSeeder.php

@@ -136,6 +136,14 @@ class ConfigurationSeeder extends Seeder
             'type'        => 'boolean',
             'description' => 'Charges the first hour worth of credits upon creating a server.'
         ]);
+        //sales tax
+        Configuration::firstOrCreate([
+            'key'   => 'SALES_TAX',
+        ], [
+            'value' => '0',
+            'type'  => 'integer',
+            'description'  => 'The %-value of tax that will be added to the product price on checkout'
+        ]);
 
     }
 }

+ 7 - 1
resources/views/admin/payments/index.blade.php

@@ -37,7 +37,10 @@
                             <th>User</th>
                             <th>Type</th>
                             <th>Amount</th>
-                            <th>Price</th>
+                            <th>Product Price</th>
+                            <th>Tax</th>
+                            <th>Tax(%)</th>
+                            <th>Total Price</th>
                             <th>Payment_ID</th>
                             <th>Payer_ID</th>
                             <th>Created at</th>
@@ -68,6 +71,9 @@
                     {data: 'type'},
                     {data: 'amount'},
                     {data: 'price'},
+                    {data: 'tax_value'},
+                    {data: 'tax_percent'},
+                    {data: 'total_price'},
                     {data: 'payment_id'},
                     {data: 'payer_id'},
                     {data: 'created_at'},

+ 1 - 1
resources/views/mail/payment/confirmed.blade.php

@@ -6,7 +6,7 @@ Your payment has been confirmed; Your credit balance has been updated.<br>
 ___
 ### Payment ID: **{{$payment->id}}**<br>
 ### Status:     **{{$payment->status}}**<br>
-### Price:      **{{$payment->formatCurrency()}}**<br>
+### Price:      **{{$payment->formatToCurrency($payment->total_price)}}**<br>
 ### Type:       **{{$payment->type}}**<br>
 ### Amount:     **{{$payment->amount}}**<br>
 ### Balance:    **{{$payment->user->credits}}**<br>

+ 55 - 27
resources/views/servers/create.blade.php

@@ -101,7 +101,7 @@
                                                 name="nest"
                                                 id="nest"
                                                 x-model="selectedNest"
-                                                @change="setNests();">
+                                                @change="setEggs();">
                                             <option selected disabled hidden
                                                     value="null">{{count($nests) > 0 ? __('Please select software ...') : __('---')}}</option>
                                             @foreach ($nests as $nest)
@@ -229,33 +229,39 @@
                                         <small x-text="selectedProductObject?.name ?? '{{__('No selection')}}'"
                                                class="text-muted"></small>
                                     </div>
+                                    
                                     <template x-if="selectedProductObject?.name">
-                                       <ul class="pl-0">
-                                           <li class="d-flex justify-content-between">
-                                               <small class="text-muted d-inline-block">{{__('CPU')}}</small>
-                                               <small class="text-muted d-inline-block" x-text="selectedProductObject.cpu + ' %'"></small>
-                                           </li>
-                                           <div class="d-flex justify-content-between">
-                                               <small class="text-muted d-inline-block">{{__('Memory')}}</small>
-                                               <small class="text-muted d-inline-block" x-text="selectedProductObject.memory + ' {{__('MB')}}'"></small>
-                                           </div>
-                                           <div class="d-flex justify-content-between">
-                                               <small class="text-muted d-inline-block">{{__('Disk')}}</small>
-                                               <small class="text-muted d-inline-block" x-text="selectedProductObject.disk + ' {{__('MB')}}'"></small>
-                                           </div>
-                                           <div class="d-flex justify-content-between">
-                                               <small class="text-muted d-inline-block">{{__('Databases')}}</small>
-                                               <small class="text-muted d-inline-block" x-text="selectedProductObject.databases + ' {{__('MySQL')}}'"></small>
-                                           </div>
-                                           <div class="d-flex justify-content-between">
-                                               <small class="text-muted d-inline-block">{{__('Backups')}}</small>
-                                               <small class="text-muted d-inline-block" x-text="selectedProductObject.backups"></small>
-                                           </div>
-                                           <div class="d-flex justify-content-between">
-                                               <small class="text-muted d-inline-block">{{__('Allocations (ports)')}}</small>
+                                        <ul class="pl-0">
+                                            <li class="d-flex justify-content-between">
+                                                <small class="text-muted d-inline-block">{{__('CPU')}}</small>
+                                                <small class="text-muted d-inline-block"
+                                                       x-text="selectedProductObject.cpu + ' %'"></small>
+                                            </li>
+                                            <div class="d-flex justify-content-between">
+                                                <small class="text-muted d-inline-block">{{__('Memory')}}</small>
+                                                <small class="text-muted d-inline-block"
+                                                       x-text="selectedProductObject.memory + ' {{__('MB')}}'"></small>
+                                            </div>
+                                            <div class="d-flex justify-content-between">
+                                                <small class="text-muted d-inline-block">{{__('Disk')}}</small>
+                                                <small class="text-muted d-inline-block"
+                                                       x-text="selectedProductObject.disk + ' {{__('MB')}}'"></small>
+                                            </div>
+                                            <div class="d-flex justify-content-between">
+                                                <small class="text-muted d-inline-block">{{__('Databases')}}</small>
+                                                <small class="text-muted d-inline-block"
+                                                       x-text="selectedProductObject.databases + ' {{__('MySQL')}}'"></small>
+                                            </div>
+                                            <div class="d-flex justify-content-between">
+                                                <small class="text-muted d-inline-block">{{__('Backups')}}</small>
+                                                <small class="text-muted d-inline-block"
+                                                       x-text="selectedProductObject.backups"></small>
+                                            </div>
+                                            <div class="d-flex justify-content-between">
+                                               <small class="text-muted d-inline-block">{{__('Allocations')}} ({{__('ports')}})</small>
                                                <small class="text-muted d-inline-block" x-text="selectedProductObject.allocations"></small>
                                            </div>
-                                       </ul>
+                                        </ul>
                                     </template>
 
                                 </li>
@@ -319,7 +325,7 @@
                  * @note called whenever a nest is selected
                  * @see selectedNest
                  */
-                setNests() {
+                async setEggs() {
                     this.fetchedLocations = false;
                     this.fetchedProducts = false;
                     this.locations = [];
@@ -329,6 +335,14 @@
                     this.selectedProduct = 'null';
 
                     this.eggs = this.eggsSave.filter(egg => egg.nest_id == this.selectedNest)
+
+                    //automatically select the first entry if there is only 1
+                    if (this.eggs.length === 1) {
+                        this.selectedEgg = this.eggs[0].id;
+                        await this.fetchLocations();
+                        return;
+                    }
+
                     this.updateSelectedObjects()
                 },
 
@@ -351,6 +365,14 @@
 
                     this.fetchedLocations = true;
                     this.locations = response.data
+
+                    //automatically select the first entry if there is only 1
+                    if (this.locations.length === 1 && this.locations[0]?.nodes?.length === 1) {
+                        this.selectedNode = this.locations[0].id;
+                        await this.fetchProducts();
+                        return;
+                    }
+
                     this.loading = false;
                     this.updateSelectedObjects()
                 },
@@ -366,11 +388,17 @@
                     this.products = [];
                     this.selectedProduct = 'null';
 
-                    let response = await axios.get(`{{route('products.products.node')}}/${this.selectedNode}`)
+                    let response = await axios.get(`{{route('products.products.node')}}/${this.selectedEgg}/${this.selectedNode}`)
                         .catch(console.error)
 
                     this.fetchedProducts = true;
                     this.products = response.data
+
+                    //automatically select the first entry if there is only 1
+                    if (this.products.length === 1) {
+                        this.selectedProduct = this.products[0].id;
+                    }
+
                     this.loading = false;
                     this.updateSelectedObjects()
                 },

+ 5 - 5
resources/views/store/checkout.blade.php

@@ -83,7 +83,7 @@
                                         <td>1</td>
                                         <td><i class="fa fa-coins mr-2"></i>{{$product->quantity}} {{strtolower($product->type) == 'credits' ? CREDITS_DISPLAY_NAME : $product->type}}</td>
                                         <td>{{$product->description}}</td>
-                                        <td>{{$product->formatCurrency()}}</td>
+                                        <td>{{$product->formatToCurrency($product->price)}}</td>
                                     </tr>
                                     </tbody>
                                 </table>
@@ -111,11 +111,11 @@
                                     <table class="table">
                                         <tr>
                                             <th style="width:50%">Subtotal:</th>
-                                            <td>{{$product->formatCurrency()}}</td>
+                                            <td>{{$product->formatToCurrency($product->price)}}</td>
                                         </tr>
                                         <tr>
-                                            <th>Tax (0%)</th>
-                                            <td>0.00</td>
+                                            <th>Tax ({{$taxpercent}}%)</th>
+                                            <td>{{$product->formatToCurrency($taxvalue)}}</td>
                                         </tr>
                                         <tr>
                                             <th>Quantity:</th>
@@ -123,7 +123,7 @@
                                         </tr>
                                         <tr>
                                             <th>Total:</th>
-                                            <td>{{$product->formatCurrency()}}</td>
+                                            <td>{{$product->formatToCurrency($total)}}</td>
                                         </tr>
                                     </table>
                                 </div>

+ 1 - 1
resources/views/store/index.blade.php

@@ -50,7 +50,7 @@
                             <?php /** @var $product PaypalProduct */?>
                             @foreach($products as $product)
                                 <tr>
-                                    <td>{{$product->formatCurrency()}}</td>
+                                    <td>{{$product->formatToCurrency($product->price)}}</td>
                                     <td>{{strtolower($product->type) == 'credits' ? CREDITS_DISPLAY_NAME : $product->type}}</td>
                                     <td><i class="fa fa-coins mr-2"></i>{{$product->display}}</td>
                                     <td><a href="{{route('checkout' , $product->id)}}" class="btn btn-info">Purchase</a>

+ 1 - 1
routes/web.php

@@ -58,7 +58,7 @@ Route::middleware(['auth', 'checkSuspended'])->group(function () {
     #routes made for server create page to fetch product info
     Route::get('/products/nodes/egg/{egg?}', [FrontProductController::class, 'getNodesBasedOnEgg'])->name('products.nodes.egg');
     Route::get('/products/locations/egg/{egg?}', [FrontProductController::class, 'getLocationsBasedOnEgg'])->name('products.locations.egg');
-    Route::get('/products/products/node/{node?}', [FrontProductController::class, 'getProductsBasedOnNode'])->name('products.products.node');
+    Route::get('/products/products/{egg?}/{node?}', [FrontProductController::class, 'getProductsBasedOnNode'])->name('products.products.node');
 
     #payments
     Route::get('checkout/{paypalProduct}', [PaymentController::class, 'checkOut'])->name('checkout');