temporarily remove the transaction
Dec 17, 2024
13
Level 1
API Returns 200 OK but Resource Not Created in Laravel
Hi everyone,
I'm facing an issue where my SaleOrder store endpoint returns 200 OK, but the resource is not created in the database.
I have another similar repository for creating Product and associating RawMaterial in a many-to-many relationship, and it works perfectly. I tried to structure the SaleOrder store method similarly, but it does not behave as expected.
Here is the follow models that structured the relationships in my laravel API.
- SaleOrder Model :
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Models\Product;
class SaleOrder extends Model
{
use HasFactory;
protected $fillable = [
'payment_method',
'order_date',
'payment_status',
'order_status',
'discount_percentage',
'discount_value_in_riel',
'discount_value_in_usd',
'tax_percentage',
'tax_value_in_riel',
'tax_value_in_usd',
'sub_total_in_riel',
'sub_total_in_usd',
'grand_total_with_tax_in_riel',
'grand_total_with_tax_in_usd',
'grand_total_without_tax_in_riel',
'grand_total_without_tax_in_usd',
'clearing_payable_percentage',
'indebted_in_riel',
'indebted_in_usd',
];
public function products()
{
return $this->belongsToMany(Product::class, 'product_sale_orders')
->withPivot('quantity_sold');
}
}
- Product Model :
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Models\RawMaterial;
use App\Models\ProductRawMaterial;
use App\Models\SaleOrder;
use App\Models\ProductCategory;
use App\Models\ProductImage;
use Illuminate\Database\Eloquent\SoftDeletes;
class Product extends Model
{
use HasFactory;
use SoftDeletes;
protected $fillable = [
'staging_date',
'product_name',
'product_code',
'quantity',
'remaining_quantity',
'minimum_stock_level',
'unit_of_measurement',
'package_size',
'warehouse_location',
'unit_price_in_usd',
'total_value_in_usd',
'exchange_rate_from_usd_to_riel',
'unit_price_in_riel',
'total_value_in_riel',
'exchange_rate_from_riel_to_usd',
'description',
'status',
'product_category_id',
'barcode'
];
public function sale_orders()
{
return $this->belongsToMany(SaleOrder::class, 'product_sale_orders')
->withPivot('quantity_sold');
}
}
- ProductSaleOrder Model (Pivot Model)
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Models\Product;
use App\Models\SaleOrder;
class ProductSaleOrder extends Model
{
use HasFactory;
protected $table = 'product_sale_orders';
protected $fillable = [
'product_id',
'sale_order_id',
'quantity_sold',
];
public function product()
{
return $this->belongsTo(Product::class);
}
public function sale_order()
{
return $this->belongsTo(SaleOrder::class);
}
}
Here is my controller logic to creat resource but it return status code 200 OK instead of status code 201 :
public function store(Request $request)
{
$validated = $request->validate([
'payment_method' => 'required|string|max:50',
'order_date' => 'required|date',
'payment_status' => 'required|string',
'order_status' => 'required|string',
'discount_percentage' => 'required|numeric|min:0|max:100',
'tax_percentage' => 'required|numeric|min:0|max:100',
'clearing_payable_percentage' => 'required|numeric|min:0|max:100',
'products' => 'required|array',
'products.*.product_id' => 'required|exists:products,id',
'products.*.quantity_sold' => 'required|integer|min:1',
]);
DB::beginTransaction();
try {
// Step 1: Calculate total values from the product array
$subTotalUSD = 0;
$subTotalRiel = 0;
foreach ($validated['products'] as $productInput) {
$product = Product::findOrFail($productInput['product_id']);
// Check if remaining quantity is sufficient
if ($product->remaining_quantity < $productInput['quantity_sold']) {
throw new \Exception("Quantity of product ID {$product->id} is not enough.");
}
// Add product's price to sub-total
$subTotalUSD += $product->unit_price_in_usd * $productInput['quantity_sold'];
$subTotalRiel += $product->unit_price_in_riel * $productInput['quantity_sold'];
// Update remaining quantity
$product->remaining_quantity -= $productInput['quantity_sold'];
$product->save();
}
// Step 2: Calculate discount, tax, and indebted values
$discountValueUSD = $subTotalUSD * ($validated['discount_percentage'] / 100);
$discountValueRiel = $subTotalRiel * ($validated['discount_percentage'] / 100);
$taxValueUSD = $subTotalUSD * ($validated['tax_percentage'] / 100);
$taxValueRiel = $subTotalRiel * ($validated['tax_percentage'] / 100);
$grandTotalUSD = $subTotalUSD - $discountValueUSD + $taxValueUSD;
$grandTotalRiel = $subTotalRiel - $discountValueRiel + $taxValueRiel;
$indebtedUSD = $grandTotalUSD * ($validated['clearing_payable_percentage'] / 100);
$indebtedRiel = $grandTotalRiel * ($validated['clearing_payable_percentage'] / 100);
$payment_status = 'PAID';
if ($request->clearing_payable_percentage == 0) {
$payment_status = 'UNPAID';
} elseif ($request->clearing_payable_percentage < 100) {
$payment_status = 'INDEBTED';
} elseif ($request->clearing_payable_percentage > 100) {
$payment_status = 'OVERPAID';
}
// Step 3: Create the sale order
$saleOrder = SaleOrder::create([
'payment_method' => $validated['payment_method'],
'order_date' => $validated['order_date'],
'payment_status' => $payment_status,
'order_status' => $validated['order_status'],
'discount_percentage' => $validated['discount_percentage'],
'discount_value_in_usd' => $discountValueUSD,
'discount_value_in_riel' => $discountValueRiel,
'tax_percentage' => $validated['tax_percentage'],
'tax_value_in_usd' => $taxValueUSD,
'tax_value_in_riel' => $taxValueRiel,
'sub_total_in_usd' => $subTotalUSD,
'sub_total_in_riel' => $subTotalRiel,
'grand_total_with_tax_in_usd' => $grandTotalUSD,
'grand_total_with_tax_in_riel' => $grandTotalRiel,
'grand_total_without_tax_in_usd' => $subTotalUSD - $discountValueUSD,
'grand_total_without_tax_in_riel' => $subTotalRiel - $discountValueRiel,
'clearing_payable_percentage' => $validated['clearing_payable_percentage'],
'indebted_in_usd' => $indebtedUSD,
'indebted_in_riel' => $indebtedRiel,
]);
// Step 4: Create ProductSaleOrder records for each product
foreach ($validated['products'] as $productInput) {
ProductSaleOrder::create([
'sale_order_id' => $saleOrder->id,
'product_id' => $productInput['product_id'],
'quantity_sold' => $productInput['quantity_sold'],
]);
}
DB::commit();
return response()->json([
'message' => 'Sale order created successfully.',
'sale_order' => $saleOrder,
], 201);
} catch (ValidationException $e) {
return response()->json(['errors' => $e->errors()], 400);
} catch (\Exception $e) {
DB::rollBack();
return response()->json([
'error' => $e->getMessage(),
], 400);
}
}
The Problem
- The endpoint validates the data successfully.
- It also runs without any errors and returns 200 OK or 201 Created.
- However, the resource (SaleOrder) is not being created in the database, nor are the related - ProductSaleOrder records.
Please or to participate in this conversation.