Work on tests
This commit is contained in:
parent
efe78bb49f
commit
b320915fc1
@ -20,6 +20,5 @@ enum IconEnum: string
|
||||
|
||||
case TAB_ALL = 'lucide-layout-grid';
|
||||
case TAB_OVERDUE = 'lucide-calendar-clock';
|
||||
case TAB_UNPRINTED = ' lucide-printer';
|
||||
|
||||
case TAB_UNPRINTED = 'lucide-printer';
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
use App\Enums\IconEnum;
|
||||
use App\Enums\InvoiceStatus;
|
||||
use App\Filament\Admin\Resources\InvoiceResource;
|
||||
use App\Models\Invoice;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Components\Tab;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
@ -22,12 +21,6 @@ public function getTabs(): array
|
||||
|
||||
'unpaid' => Tab::make('Unpaid')
|
||||
->query(fn ($query) => $query->where('status', InvoiceStatus::UNPAID))
|
||||
->badge(function () {
|
||||
$count = Invoice::where('status', InvoiceStatus::UNPAID)->count();
|
||||
|
||||
return $count > 0 ? $count : null;
|
||||
})
|
||||
->badgeColor(InvoiceStatus::UNPAID->getColor())
|
||||
->icon(InvoiceStatus::UNPAID->getIcon()),
|
||||
|
||||
'paid' => Tab::make('Paid')
|
||||
|
@ -125,6 +125,10 @@ public static function form(Form $form): Form
|
||||
|
||||
Section::make()
|
||||
->schema([
|
||||
Placeholder::make('ID')
|
||||
->label('Order ID')
|
||||
->content(fn (Order $record): ?string => $record->internal_po),
|
||||
|
||||
Placeholder::make('created_at')
|
||||
->label('Created')
|
||||
->content(fn (Order $record): ?string => $record->created_at?->diffForHumans()),
|
||||
|
@ -12,6 +12,7 @@
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
#[ObservedBy(InvoiceObserver::class)]
|
||||
|
||||
@ -42,16 +43,20 @@ class Invoice extends Model
|
||||
'has_gst' => 'boolean',
|
||||
'has_pst' => 'boolean',
|
||||
'date' => 'datetime',
|
||||
'total' => 'decimal:2',
|
||||
'subtotal' => 'decimal:2',
|
||||
'status' => InvoiceStatus::class,
|
||||
'subtotal' => 'float',
|
||||
'pst_amount' => 'float',
|
||||
'gst_amount' => 'float',
|
||||
'total' => 'float',
|
||||
];
|
||||
|
||||
public function calculateTotals(): void
|
||||
{
|
||||
$this->refresh();
|
||||
$this->loadMissing('orders');
|
||||
|
||||
if ($this->orders->isEmpty()) {
|
||||
|
||||
$this->subtotal = 0;
|
||||
$this->gst_amount = 0;
|
||||
$this->pst_amount = 0;
|
||||
@ -61,7 +66,10 @@ public function calculateTotals(): void
|
||||
}
|
||||
|
||||
$subtotal = $this->orders->sum(fn (Order $order) => $order->total_service_price);
|
||||
Log::debug('subtotal: '.$subtotal);
|
||||
|
||||
$this->subtotal = $subtotal;
|
||||
$this->saveQuietly();
|
||||
|
||||
$gstAmount = $this->calculateTaxAmount($subtotal, $this->gst_rate, $this->has_gst);
|
||||
$pstAmount = $this->calculateTaxAmount($subtotal, $this->pst_rate, $this->has_pst);
|
||||
|
@ -4,8 +4,10 @@
|
||||
|
||||
use App\Enums\OrderStatus;
|
||||
use App\Enums\OrderType;
|
||||
use App\Observers\OrderObserver;
|
||||
use Database\Factories\OrderFactory;
|
||||
use DateTimeInterface;
|
||||
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
@ -15,6 +17,8 @@
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
#[ObservedBy(OrderObserver::class)]
|
||||
|
||||
class Order extends Model
|
||||
{
|
||||
/** @use HasFactory<OrderFactory> */
|
||||
@ -52,6 +56,15 @@ class Order extends Model
|
||||
protected $casts = [
|
||||
'status' => OrderStatus::class,
|
||||
'order_type' => OrderType::class,
|
||||
'rush' => 'bool',
|
||||
'repeat' => 'bool',
|
||||
'new_art' => 'bool',
|
||||
'event' => 'bool',
|
||||
'digitizing' => 'bool',
|
||||
'garments' => 'bool',
|
||||
'supplied_file' => 'bool',
|
||||
'printed' => 'bool',
|
||||
'pre_production' => 'bool',
|
||||
];
|
||||
|
||||
public static function boot(): void
|
||||
@ -109,13 +122,13 @@ public function getTotalProductQuantityAttribute(): int
|
||||
|
||||
public function getTotalServicePriceAttribute(): float
|
||||
{
|
||||
$total = 0;
|
||||
$total = 0.00;
|
||||
|
||||
foreach ($this->productServices as $service) {
|
||||
$total += $service->amount * $service->amount_price;
|
||||
}
|
||||
|
||||
return number_format($total, 2);
|
||||
return $total;
|
||||
}
|
||||
|
||||
public function active(): bool
|
||||
|
@ -2,12 +2,16 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Observers\ProductServiceObserver;
|
||||
use Database\Factories\ProductServiceFactory;
|
||||
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
#[ObservedBy(ProductServiceObserver::class)]
|
||||
|
||||
class ProductService extends Model
|
||||
{
|
||||
/** @use HasFactory<ProductServiceFactory> */
|
||||
@ -38,6 +42,10 @@ public function getServiceDetailsAttribute(): string
|
||||
{
|
||||
$file = $this->serviceFile;
|
||||
|
||||
if (! $file) {
|
||||
return 'Error: could not find service file';
|
||||
}
|
||||
|
||||
return $file->name.', '.$this->placement.', '.$file->width.' W, '.$file->height.' H';
|
||||
}
|
||||
|
||||
|
65
app/Observers/OrderObserver.php
Normal file
65
app/Observers/OrderObserver.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\Observers;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Order;
|
||||
|
||||
class OrderObserver
|
||||
{
|
||||
/**
|
||||
* Handle the Order "created" event.
|
||||
*/
|
||||
public function created(Order $order): void
|
||||
{
|
||||
if ($order->invoice()->exists()) {
|
||||
$order->invoice->calculateTotals();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Order "updated" event.
|
||||
*/
|
||||
public function updated(Order $order): void
|
||||
{
|
||||
if ($order->invoice()->exists()) {
|
||||
$order->invoice->calculateTotals();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Order "saving" event.
|
||||
*/
|
||||
public function saved(Order $order): void
|
||||
{
|
||||
if ($order->isDirty(['invoice_id']) && Invoice::where('id', $order->invoice_id)->exists()) {
|
||||
$order->invoice->calculateTotals();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Order "deleted" event.
|
||||
*/
|
||||
public function deleted(Order $order): void
|
||||
{
|
||||
if ($order->invoice()->exists()) {
|
||||
$order->invoice->calculateTotals();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Order "restored" event.
|
||||
*/
|
||||
public function restored(Order $order): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Order "force deleted" event.
|
||||
*/
|
||||
public function forceDeleted(Order $order): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
64
app/Observers/ProductServiceObserver.php
Normal file
64
app/Observers/ProductServiceObserver.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace App\Observers;
|
||||
|
||||
use App\Models\ProductService;
|
||||
|
||||
class ProductServiceObserver
|
||||
{
|
||||
/**
|
||||
* Handle the ProductService "created" event.
|
||||
*/
|
||||
public function created(ProductService $productService): void
|
||||
{
|
||||
$this->calculateInvoiceTotalsIfExists($productService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the ProductService "updated" event.
|
||||
*/
|
||||
public function updated(ProductService $productService): void
|
||||
{
|
||||
$this->calculateInvoiceTotalsIfExists($productService);
|
||||
}
|
||||
|
||||
public function saved(ProductService $productService): void
|
||||
{
|
||||
$this->calculateInvoiceTotalsIfExists($productService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the ProductService "deleted" event.
|
||||
*/
|
||||
public function deleted(ProductService $productService): void
|
||||
{
|
||||
$this->calculateInvoiceTotalsIfExists($productService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the ProductService "restored" event.
|
||||
*/
|
||||
public function restored(ProductService $productService): void
|
||||
{
|
||||
$this->calculateInvoiceTotalsIfExists($productService);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the ProductService "force deleted" event.
|
||||
*/
|
||||
public function forceDeleted(ProductService $productService): void
|
||||
{
|
||||
$this->calculateInvoiceTotalsIfExists($productService);
|
||||
}
|
||||
|
||||
private function calculateInvoiceTotalsIfExists(ProductService $productService): void
|
||||
{
|
||||
if ($productService->order()->exists()) {
|
||||
if ($productService->order->invoice()->exists()) {
|
||||
|
||||
$productService->order->invoice->calculateTotals();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ class CustomerFactory extends Factory
|
||||
{
|
||||
protected $model = Customer::class;
|
||||
|
||||
public function definition()
|
||||
public function definition(): array
|
||||
{
|
||||
$company_name = $this->faker->company();
|
||||
$internal_name = explode(',', $company_name);
|
||||
|
@ -15,7 +15,7 @@ class InvoiceFactory extends Factory
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
$customer = Customer::all()->shuffle()->first();
|
||||
$customer = Customer::all()->shuffle()->firstOrFail();
|
||||
|
||||
return [
|
||||
'created_at' => Carbon::now()->subDays(rand(1, 30)),
|
||||
|
@ -1,50 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Enums\InvoiceStatus;
|
||||
use App\Filament\Admin\Resources\InvoiceResource\Pages\CreateInvoice;
|
||||
use App\Models\Customer;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\TaxRate;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
it('can create an invoice', function () {
|
||||
$customer = Customer::factory()->create(); // Generates a customer
|
||||
$user = User::factory(['is_admin' => true])->create();
|
||||
$pst_rate = TaxRate::where('name', 'PST')->value('value') ?? 0;
|
||||
$gst_rate = TaxRate::where('name', 'GST')->value('value') ?? 0;
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$formData = [
|
||||
'customer_id' => $customer->id,
|
||||
'date' => now()->toDateString(),
|
||||
'due_date' => now()->addDays(7)->toDateString(),
|
||||
'status' => InvoiceStatus::UNPAID->value,
|
||||
'has_gst' => true,
|
||||
'has_pst' => true,
|
||||
];
|
||||
|
||||
// Step 3: Submit the form and create an invoice
|
||||
$this->livewire(CreateInvoice::class)
|
||||
->fillForm($formData) // Simulates filling the form
|
||||
->call('create') // Submits the form
|
||||
->assertHasNoErrors(); // Verifies no validation errors occurred
|
||||
|
||||
// Step 4: Assert the invoice was successfully created in the database
|
||||
$this->assertDatabaseHas('invoices', [
|
||||
'internal_id' => 'INV400001',
|
||||
'customer_id' => $formData['customer_id'],
|
||||
'status' => $formData['status'],
|
||||
'has_gst' => $formData['has_gst'],
|
||||
'has_pst' => $formData['has_pst'],
|
||||
'gst_rate' => $gst_rate,
|
||||
'pst_rate' => $pst_rate,
|
||||
]);
|
||||
});
|
||||
|
||||
// it can add orders
|
||||
|
||||
// it correctly calculates tax
|
@ -11,9 +11,18 @@
|
||||
|
|
||||
*/
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
pest()->extend(Tests\TestCase::class)
|
||||
->use(Illuminate\Foundation\Testing\RefreshDatabase::class)
|
||||
->in('Feature');
|
||||
// ->use(Illuminate\Foundation\Testing\DatabaseMigrations::class)
|
||||
// ->use(RefreshDatabase::class)
|
||||
->beforeEach(function () {
|
||||
DB::beginTransaction();
|
||||
})
|
||||
->afterEach(function () {
|
||||
DB::rollBack();
|
||||
})
|
||||
->in('Unit');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@ -26,9 +35,9 @@
|
||||
|
|
||||
*/
|
||||
|
||||
expect()->extend('toBeOne', function () {
|
||||
return $this->toBe(1);
|
||||
});
|
||||
//expect()->extend('toBeOne', function () {
|
||||
// return $this->toBe(1);
|
||||
//});
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
254
tests/Unit/InvoiceTest.php
Normal file
254
tests/Unit/InvoiceTest.php
Normal file
@ -0,0 +1,254 @@
|
||||
<?php
|
||||
|
||||
use App\Enums\InvoiceStatus;
|
||||
use App\Filament\Admin\Resources\InvoiceResource\Pages\CreateInvoice;
|
||||
use App\Models\Customer;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Order;
|
||||
use App\Models\ProductService;
|
||||
use App\Models\TaxRate;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
it('can create an invoice', function () {
|
||||
$user = User::factory(['is_admin' => true])->create();
|
||||
$this->actingAs($user);
|
||||
|
||||
$customer = Customer::factory()->create(); // Generates a customer
|
||||
$pst_rate = TaxRate::where('name', 'PST')->value('value') ?? 0;
|
||||
$gst_rate = TaxRate::where('name', 'GST')->value('value') ?? 0;
|
||||
|
||||
$formData = [
|
||||
'customer_id' => $customer->id,
|
||||
'date' => now()->toDateString(),
|
||||
'due_date' => now()->addDays(7)->toDateString(),
|
||||
'status' => InvoiceStatus::UNPAID->value,
|
||||
'has_gst' => true,
|
||||
'has_pst' => true,
|
||||
];
|
||||
|
||||
$this->livewire(CreateInvoice::class)
|
||||
->fillForm($formData)
|
||||
->call('create')
|
||||
->assertHasNoErrors();
|
||||
|
||||
$this->assertDatabaseHas('invoices', [
|
||||
'internal_id' => 'INV400001',
|
||||
'customer_id' => $formData['customer_id'],
|
||||
'status' => $formData['status'],
|
||||
'has_gst' => $formData['has_gst'],
|
||||
'has_pst' => $formData['has_pst'],
|
||||
'gst_rate' => $gst_rate,
|
||||
'pst_rate' => $pst_rate,
|
||||
]);
|
||||
|
||||
$invoice = Invoice::where('internal_id', 'INV400001')->firstOrFail();
|
||||
|
||||
$this->assertEquals($invoice->orders->isEmpty(), true);
|
||||
});
|
||||
|
||||
it('can add orders to an invoice', function () {
|
||||
$customer = Customer::factory()->create();
|
||||
$invoice = Invoice::factory()->create(['customer_id' => $customer->id]);
|
||||
$orders = Order::factory()->for($customer)->count(3)->create();
|
||||
|
||||
$invoice->orders()->saveMany($orders);
|
||||
|
||||
$this->assertEquals($invoice->orders->count(), 3);
|
||||
});
|
||||
|
||||
it('correctly calculates tax amounts', function () {
|
||||
/** Setup **/
|
||||
$customer = Customer::factory()->create();
|
||||
$order = Order::factory()
|
||||
->for($customer)
|
||||
->has(ProductService::factory()->count(3))
|
||||
->create();
|
||||
|
||||
$invoice = Invoice::factory(['has_gst' => true, 'has_pst' => true])->create(['customer_id' => $customer->id]);
|
||||
$order->invoice()->associate($invoice)->save();
|
||||
|
||||
/** Action **/
|
||||
$subtotal = $order->total_service_price;
|
||||
$pst_amount = $subtotal * $invoice->pst_rate / 100;
|
||||
$gst_amount = $subtotal * $invoice->gst_rate / 100;
|
||||
$total = $subtotal + $pst_amount + $gst_amount;
|
||||
|
||||
/** Assertions **/
|
||||
$this->assertSame($invoice->subtotal, $subtotal);
|
||||
$this->assertSame($invoice->gst_amount, $gst_amount);
|
||||
$this->assertSame($invoice->pst_amount, $pst_amount);
|
||||
$this->assertSame($invoice->total, $total);
|
||||
});
|
||||
|
||||
it('correctly re-calculates tax amounts when a product service gets added to an order', function () {
|
||||
/** Setup **/
|
||||
$customer = Customer::factory()->create();
|
||||
$invoice = Invoice::factory(['has_gst' => true, 'has_pst' => true])->create(['customer_id' => $customer->id]);
|
||||
$order = Order::factory()->for($customer)->create();
|
||||
|
||||
$order->invoice()->associate($invoice)->save();
|
||||
|
||||
ProductService::factory()->create(['order_id' => $order->id]);
|
||||
|
||||
/** Action **/
|
||||
$subtotal = $order->total_service_price;
|
||||
$pst_amount = $subtotal * $invoice->pst_rate / 100;
|
||||
$gst_amount = $subtotal * $invoice->gst_rate / 100;
|
||||
$total = $subtotal + $pst_amount + $gst_amount;
|
||||
|
||||
$invoice->refresh();
|
||||
|
||||
/** Assertions **/
|
||||
$this->assertSame($invoice->subtotal, $subtotal);
|
||||
$this->assertSame($invoice->gst_amount, $gst_amount);
|
||||
$this->assertSame($invoice->pst_amount, $pst_amount);
|
||||
$this->assertSame($invoice->total, $total);
|
||||
});
|
||||
|
||||
it('correctly re-calculates tax amounts when a product service gets removed from an order', function () {
|
||||
/** Setup **/
|
||||
$customer = Customer::factory()->create();
|
||||
$invoice = Invoice::factory(['has_gst' => true, 'has_pst' => true])->create(['customer_id' => $customer->id]);
|
||||
$order = Order::factory()->for($customer)->create();
|
||||
|
||||
$order->invoice()->associate($invoice)->save();
|
||||
|
||||
$productService1 = ProductService::factory()->create(['order_id' => $order->id]);
|
||||
$productService2 = ProductService::factory()->create(['order_id' => $order->id]);
|
||||
|
||||
/** Action **/
|
||||
$productService2->delete(); // Remove one product service
|
||||
|
||||
$order->refresh();
|
||||
$invoice->refresh();
|
||||
|
||||
$subtotal = $order->total_service_price;
|
||||
$pstAmount = $subtotal * $invoice->pst_rate / 100;
|
||||
$gstAmount = $subtotal * $invoice->gst_rate / 100;
|
||||
$total = $subtotal + $pstAmount + $gstAmount;
|
||||
|
||||
/** Assertions **/
|
||||
$this->assertSame($invoice->subtotal, $subtotal);
|
||||
$this->assertSame($invoice->pst_amount, $pstAmount);
|
||||
$this->assertSame($invoice->gst_amount, $gstAmount);
|
||||
$this->assertSame($invoice->total, $total);
|
||||
});
|
||||
|
||||
it('correctly re-calculates tax amounts when an order gets added', function () {
|
||||
/** Setup **/
|
||||
$customer = Customer::factory()->create();
|
||||
$order = Order::factory()->for($customer)->create();
|
||||
|
||||
ProductService::factory()->count(3)->create(['order_id' => $order->id]);
|
||||
|
||||
$invoice = Invoice::factory(['has_gst' => true, 'has_pst' => true])->create(['customer_id' => $customer->id]);
|
||||
$order->invoice()->associate($invoice)->save();
|
||||
|
||||
/** Action **/
|
||||
$newOrder = Order::factory()->for($customer)->create();
|
||||
ProductService::factory()->count(3)->create(['order_id' => $newOrder->id]);
|
||||
|
||||
$newOrder->invoice()->associate($invoice)->save();
|
||||
|
||||
$subtotal = $order->total_service_price + $newOrder->total_service_price;
|
||||
$pst_amount = $subtotal * $invoice->pst_rate / 100;
|
||||
$gst_amount = $subtotal * $invoice->gst_rate / 100;
|
||||
$total = $subtotal + $pst_amount + $gst_amount;
|
||||
|
||||
/** Assertions **/
|
||||
$this->assertSame($invoice->orders->count(), 2);
|
||||
$this->assertSame($invoice->subtotal, $subtotal);
|
||||
$this->assertSame($invoice->gst_amount, $gst_amount);
|
||||
$this->assertSame($invoice->pst_amount, $pst_amount);
|
||||
$this->assertSame($invoice->total, $total);
|
||||
});
|
||||
|
||||
it('correctly re-calculates tax amounts when an order gets removed', function () {
|
||||
/** Setup **/
|
||||
$customer = Customer::factory()->create();
|
||||
$orders = Order::factory()->for($customer)
|
||||
->has(ProductService::factory()->count(2))
|
||||
->count(2)
|
||||
->create();
|
||||
|
||||
$invoice = Invoice::factory(['has_gst' => true, 'has_pst' => true])->create(['customer_id' => $customer->id]);
|
||||
$orders->each(fn (Order $order) => $order->invoice()->associate($invoice)->save());
|
||||
|
||||
$orders[0]->delete();
|
||||
|
||||
/** Action **/
|
||||
$subtotal = $orders[1]->total_service_price;
|
||||
$pst_amount = $subtotal * $invoice->pst_rate / 100;
|
||||
$gst_amount = $subtotal * $invoice->gst_rate / 100;
|
||||
$total = $subtotal + $pst_amount + $gst_amount;
|
||||
|
||||
/** Assertions **/
|
||||
$this->assertSame($invoice->orders->count(), 1);
|
||||
$this->assertSame($invoice->subtotal, $subtotal);
|
||||
$this->assertSame($invoice->gst_amount, $gst_amount);
|
||||
$this->assertSame($invoice->pst_amount, $pst_amount);
|
||||
$this->assertSame($invoice->total, $total);
|
||||
});
|
||||
|
||||
it('correctly re-calculates tax amounts when an order\'s product service\'s quantity gets changed', function () {
|
||||
$customer = Customer::factory()->create();
|
||||
$order = Order::factory()
|
||||
->for($customer)
|
||||
->has(ProductService::factory()->count(3))
|
||||
->create();
|
||||
|
||||
$invoice = Invoice::factory(['has_gst' => true, 'has_pst' => true])->create(['customer_id' => $customer->id]);
|
||||
$order->invoice()->associate($invoice)->save();
|
||||
|
||||
$service = $invoice->orders->first()->productServices->first();
|
||||
$service->amount += 10;
|
||||
$service->save();
|
||||
|
||||
$invoice->refresh();
|
||||
$order->refresh();
|
||||
|
||||
/** Action **/
|
||||
$subtotal = $order->total_service_price;
|
||||
$pst_amount = $subtotal * $invoice->pst_rate / 100;
|
||||
$gst_amount = $subtotal * $invoice->gst_rate / 100;
|
||||
$total = $subtotal + $pst_amount + $gst_amount;
|
||||
|
||||
/** Assertions **/
|
||||
$this->assertSame($invoice->subtotal, $subtotal);
|
||||
$this->assertSame($invoice->gst_amount, $gst_amount);
|
||||
$this->assertSame($invoice->pst_amount, $pst_amount);
|
||||
$this->assertSame($invoice->total, $total);
|
||||
});
|
||||
|
||||
it('correctly re-calculates tax amounts when an order\'s product service\'s amount gets changed', function () {
|
||||
$customer = Customer::factory()->create();
|
||||
$order = Order::factory()
|
||||
->for($customer)
|
||||
->has(ProductService::factory()->count(3))
|
||||
->create();
|
||||
|
||||
$invoice = Invoice::factory(['has_gst' => true, 'has_pst' => true])->create(['customer_id' => $customer->id]);
|
||||
$order->invoice()->associate($invoice)->save();
|
||||
|
||||
$service = $invoice->orders->first()->productServices->first();
|
||||
$service->amount_price += 10;
|
||||
$service->save();
|
||||
|
||||
$invoice->refresh();
|
||||
$order->refresh();
|
||||
|
||||
/** Action **/
|
||||
$subtotal = $order->total_service_price;
|
||||
$pst_amount = $subtotal * $invoice->pst_rate / 100;
|
||||
$gst_amount = $subtotal * $invoice->gst_rate / 100;
|
||||
$total = $subtotal + $pst_amount + $gst_amount;
|
||||
|
||||
/** Assertions **/
|
||||
$this->assertSame($invoice->subtotal, $subtotal);
|
||||
$this->assertSame($invoice->gst_amount, $gst_amount);
|
||||
$this->assertSame($invoice->pst_amount, $pst_amount);
|
||||
$this->assertSame($invoice->total, $total);
|
||||
});
|
@ -15,14 +15,17 @@
|
||||
use App\Models\ServiceFile;
|
||||
use App\Models\ServiceType;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
|
||||
use function Pest\Livewire\livewire;
|
||||
|
||||
uses(DatabaseMigrations::class);
|
||||
|
||||
it('can create an order and all associated models and save it to the database', function () {
|
||||
$type = fake()->randomElement(OrderType::cases());
|
||||
$status = fake()->randomElement(OrderStatus::cases());
|
||||
$customer = Customer::factory()->create();
|
||||
$contact = Contact::factory()->for($customer)->create();
|
||||
// $contact = Contact::factory()->for($customer)->create();
|
||||
$attributes = array_map(fn ($case) => $case->value, OrderAttributes::cases());
|
||||
$orderDate = today();
|
||||
$dueDate = today()->addDays(10);
|
||||
@ -144,15 +147,15 @@
|
||||
$status,
|
||||
$dueDate->format('Y-m-d'),
|
||||
'Notes go here! Here\'s the notes!',
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
]);
|
||||
|
||||
// Order Products
|
Loading…
x
Reference in New Issue
Block a user