akuntansi-sia/tests/Feature/IntegrationPurchaseToSaleTe...

266 lines
9.6 KiB
PHP

<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
use App\Models\User;
use App\Models\Branch;
use App\Models\RawMaterial;
use App\Models\Product;
use App\Models\ProductRecipe;
use App\Models\Stock;
use App\Models\JournalEntry;
class IntegrationPurchaseToSaleTest extends TestCase
{
use RefreshDatabase;
public function test_equity_and_balance_sheet_use_stock_based_modal()
{
$branch = Branch::create(['name' => 'Cabang 1']);
$admin = User::factory()->create(['role' => 'admin', 'branch' => $branch->name]);
$product = Product::create([
'name' => 'Kopi',
'category' => 'minuman',
'purchase_price' => 3000,
'selling_price' => 5000,
'branch' => $branch->name,
]);
Stock::create([
'product_id' => $product->id,
'branch' => $branch->name,
'quantity' => 3,
'unit' => 'Pcs',
]);
$response = $this->actingAs($admin)->get('/laporan/perubahan-modal');
$response->assertOk();
$response->assertViewHas('data', function ($data) {
return $data['modal_awal'] == 15000 && $data['modal_akhir'] == 15000;
});
$balanceResponse = $this->actingAs($admin)->get('/laporan/neraca-keuangan');
$balanceResponse->assertOk();
$balanceResponse->assertViewHas('data', function ($data) {
return $data['modal_akhir'] == 15000;
});
}
public function test_sale_creates_journal_entries_and_reports_reflect_sales_data()
{
$branch = Branch::create(['name' => 'Cabang 1']);
$admin = User::factory()->create(['role' => 'admin', 'branch' => $branch->name]);
$product = Product::create([
'name' => 'Kopi',
'category' => 'minuman',
'purchase_price' => 4000,
'selling_price' => 5000,
'branch' => $branch->name,
]);
Stock::create([
'product_id' => $product->id,
'branch' => $branch->name,
'quantity' => 2,
'unit' => 'Pcs',
]);
$response = $this->actingAs($admin)->post('/laporan/penjualan', [
'date' => now()->toDateString(),
'product_id' => $product->id,
'quantity' => 1,
'total_price' => 5000,
'branch' => $branch->name,
]);
$response->assertSessionHasNoErrors();
$this->assertDatabaseCount('journal_entries', 1);
$this->assertDatabaseHas('journal_entries', ['reference_type' => 'Sale']);
$pnlResponse = $this->actingAs($admin)->get('/laporan/neraca-laba-rugi');
$pnlResponse->assertOk();
$pnlResponse->assertViewHas('dataTotal', function ($data) {
return $data['penjualan'] == 5000 && $data['pembelian'] == 4000 && $data['laba_kotor'] == 1000;
});
$cashFlowResponse = $this->actingAs($admin)->get('/laporan/arus-kas');
$cashFlowResponse->assertOk();
$cashFlowResponse->assertViewHas('data', function ($data) {
return $data['penerimaan_penjualan'] == 5000 && $data['arus_kas_operasi'] == 5000;
});
}
public function test_purchase_creates_raw_material_stock_and_product_stock_then_sale_reduces_stocks()
{
// Create branch and user
$branch = Branch::create(['name' => 'Cabang 1']);
$admin = User::factory()->create(['role' => 'admin', 'branch' => $branch->name]);
// Create raw material
$rm = RawMaterial::create(['name' => 'Tepung', 'unit' => 'gram', 'stock_quantity' => 0, 'branch' => $branch->name]);
// Create product that uses 100 grams per unit
$product = Product::create([
'name' => 'Roti',
'category' => 'makanan',
'purchase_price' => 1000,
'selling_price' => 2000,
'branch' => $branch->name,
]);
ProductRecipe::create([
'product_id' => $product->id,
'raw_material_id' => $rm->id,
'quantity_needed' => 100,
]);
// Ensure no product stock initially
$this->assertDatabaseMissing('stocks', ['product_id' => $product->id, 'branch' => $branch->name, 'quantity' => 1]);
// Simulate purchase of 1000 grams (1 kilogram)
$response = $this->actingAs($admin)->post('/laporan/pembelian', [
'date' => now()->toDateString(),
'item' => 'Beli Tepung',
'quantity' => '1000 gram',
'total_price' => 100000,
'type' => 'raw_material',
'raw_material_id' => $rm->id,
'branch' => $branch->name,
]);
$response->assertSessionHasNoErrors();
$rm->refresh();
// 1000 grams purchased
$this->assertEquals(1000, $rm->stock_quantity);
// After recalculation, product stock should be floor(1000/100) = 10
$this->assertDatabaseHas('stocks', ['product_id' => $product->id, 'branch' => $branch->name, 'quantity' => 10]);
// Simulate sale of 2 units
$response2 = $this->actingAs($admin)->post('/laporan/penjualan', [
'date' => now()->toDateString(),
'product_id' => $product->id,
'quantity' => 2,
'total_price' => 4000,
'branch' => $branch->name,
]);
$response2->assertSessionHasNoErrors();
$rm->refresh();
// Raw material should be reduced by 2 * 100 = 200 grams -> remaining 800
$this->assertEquals(800, $rm->stock_quantity);
// Product stock recalculated should be floor(800/100) = 8
$this->assertDatabaseHas('stocks', ['product_id' => $product->id, 'branch' => $branch->name, 'quantity' => 8]);
}
public function test_purchase_of_liters_keeps_stock_in_liters()
{
$branch = Branch::create(['name' => 'Cabang 1']);
$admin = User::factory()->create(['role' => 'admin', 'branch' => $branch->name]);
$rm = RawMaterial::create(['name' => 'Air Galon', 'unit' => 'Liter', 'stock_quantity' => 0, 'branch' => $branch->name]);
$response = $this->actingAs($admin)->post('/laporan/pembelian', [
'date' => now()->toDateString(),
'item' => 'Beli Air Galon',
'quantity' => '30 Liter',
'total_price' => 300000,
'type' => 'raw_material',
'raw_material_id' => $rm->id,
'branch' => $branch->name,
]);
$response->assertSessionHasNoErrors();
$rm->refresh();
$this->assertEquals(30, $rm->stock_quantity);
}
public function test_sale_of_es_teh_reduces_tea_and_gallon_raw_materials()
{
$branch = Branch::create(['name' => 'Cabang 1']);
$admin = User::factory()->create(['role' => 'admin', 'branch' => $branch->name]);
$teh = RawMaterial::create(['name' => 'Teh', 'unit' => 'Gram', 'stock_quantity' => 100, 'branch' => $branch->name]);
$airGalon = RawMaterial::create(['name' => 'Air Galon', 'unit' => 'Liter', 'stock_quantity' => 10, 'branch' => $branch->name]);
$product = Product::create([
'name' => 'Es Teh',
'category' => 'minuman',
'purchase_price' => 2000,
'selling_price' => 5000,
'branch' => $branch->name,
]);
ProductRecipe::create([ 'product_id' => $product->id, 'raw_material_id' => $teh->id, 'quantity_needed' => 10 ]);
ProductRecipe::create([ 'product_id' => $product->id, 'raw_material_id' => $airGalon->id, 'quantity_needed' => 1 ]);
Stock::create(['product_id' => $product->id, 'branch' => $branch->name, 'quantity' => 10, 'unit' => 'Pcs']);
$response = $this->actingAs($admin)->post('/laporan/penjualan', [
'date' => now()->toDateString(),
'product_id' => $product->id,
'quantity' => 1,
'total_price' => 5000,
'branch' => $branch->name,
]);
$response->assertSessionHasNoErrors();
$teh->refresh();
$airGalon->refresh();
$this->assertEquals(90, $teh->stock_quantity);
$this->assertEquals(9, $airGalon->stock_quantity);
$this->assertDatabaseHas('stocks', ['product_id' => $product->id, 'branch' => $branch->name, 'quantity' => 9]);
}
public function test_sale_reduces_product_stock_for_recipe_based_product()
{
$branch = Branch::create(['name' => 'Cabang 1']);
$admin = User::factory()->create(['role' => 'admin', 'branch' => $branch->name]);
$rm = RawMaterial::create(['name' => 'Teh', 'unit' => 'gram', 'stock_quantity' => 200, 'branch' => $branch->name]);
$product = Product::create([
'name' => 'Es Teh',
'category' => 'minuman',
'purchase_price' => 2000,
'selling_price' => 5000,
'branch' => $branch->name,
]);
ProductRecipe::create([
'product_id' => $product->id,
'raw_material_id' => $rm->id,
'quantity_needed' => 20,
]);
Stock::create([
'product_id' => $product->id,
'branch' => $branch->name,
'quantity' => 10,
'unit' => 'Pcs',
]);
$response = $this->actingAs($admin)->post('/laporan/penjualan', [
'date' => now()->toDateString(),
'product_id' => $product->id,
'quantity' => 1,
'total_price' => 5000,
'branch' => $branch->name,
]);
$response->assertSessionHasNoErrors();
$rm->refresh();
$this->assertEquals(180, $rm->stock_quantity);
$this->assertDatabaseHas('stocks', ['product_id' => $product->id, 'branch' => $branch->name, 'quantity' => 9]);
}
}