mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-04-03 06:44:27 -04:00
- Create app/Libraries/Reward_lib.php with reward point business logic: - calculatePointsEarned(): calculate rewards from purchase amount - adjustRewardPoints(): deduct/restore/adjust customer points - handleCustomerChange(): handle points when customer changes on sale - adjustRewardDelta(): adjust delta for same customer payment changes - hasSufficientPoints(): validate customer has enough points - getPointsBalance(): get customer points balance - calculateRewardPaymentAmount(): sum reward payments from array - Add tests/Libraries/Reward_libTest.php with 20+ test cases covering: - Points calculation edge cases - Customer change scenarios - Deletion/restore operations - Sufficient points validation - Payment amount calculation - Update tests/phpunit.xml to include Libraries testsuite This extraction centralizes reward logic for better testability and follows the existing library pattern (Tax_lib, Sale_lib, etc.).
292 lines
9.3 KiB
PHP
292 lines
9.3 KiB
PHP
<?php
|
|
|
|
namespace Tests\Libraries;
|
|
|
|
use CodeIgniter\Test\CIUnitTestCase;
|
|
use App\Libraries\Reward_lib;
|
|
use App\Models\Customer;
|
|
|
|
class Reward_libTest extends CIUnitTestCase
|
|
{
|
|
use \CodeIgniter\Test\DatabaseTestTrait;
|
|
|
|
protected $migrate = true;
|
|
protected $migrateOnce = true;
|
|
protected $refresh = true;
|
|
protected $namespace = null;
|
|
|
|
private Reward_lib $rewardLib;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->rewardLib = new Reward_lib();
|
|
}
|
|
|
|
/**
|
|
* Test calculatePointsEarned returns correct calculation
|
|
*/
|
|
public function testCalculatePointsEarnedReturnsCorrectValue(): void
|
|
{
|
|
$pointsEarned = $this->rewardLib->calculatePointsEarned(100.00, 10);
|
|
$this->assertEquals(10.0, $pointsEarned);
|
|
}
|
|
|
|
/**
|
|
* Test calculatePointsEarned with zero amount
|
|
*/
|
|
public function testCalculatePointsEarnedWithZeroAmount(): void
|
|
{
|
|
$pointsEarned = $this->rewardLib->calculatePointsEarned(0, 10);
|
|
$this->assertEquals(0.0, $pointsEarned);
|
|
}
|
|
|
|
/**
|
|
* Test calculatePointsEarned with zero percentage
|
|
*/
|
|
public function testCalculatePointsEarnedWithZeroPercentage(): void
|
|
{
|
|
$pointsEarned = $this->rewardLib->calculatePointsEarned(100.00, 0);
|
|
$this->assertEquals(0.0, $pointsEarned);
|
|
}
|
|
|
|
/**
|
|
* Test calculatePointsEarned with percentage over 100
|
|
*/
|
|
public function testCalculatePointsEarnedWithHighPercentage(): void
|
|
{
|
|
$pointsEarned = $this->rewardLib->calculatePointsEarned(50.00, 200);
|
|
$this->assertEquals(100.0, $pointsEarned);
|
|
}
|
|
|
|
/**
|
|
* Test hasSufficientPoints returns true when customer has enough points
|
|
*/
|
|
public function testHasSufficientPointsReturnsTrueWhenSufficient(): void
|
|
{
|
|
$customerModel = $this->getMockBuilder(Customer::class)
|
|
->onlyMethods(['get_info'])
|
|
->getMock();
|
|
|
|
$customerModel->method('get_info')
|
|
->willReturn((object)['points' => 100]);
|
|
|
|
// Use reflection to inject mock
|
|
$reflection = new \ReflectionClass($this->rewardLib);
|
|
$property = $reflection->getProperty('customer');
|
|
$property->setAccessible(true);
|
|
$property->setValue($this->rewardLib, $customerModel);
|
|
|
|
$this->assertTrue($this->rewardLib->hasSufficientPoints(1, 50));
|
|
}
|
|
|
|
/**
|
|
* Test hasSufficientPoints returns false when customer has insufficient points
|
|
*/
|
|
public function testHasSufficientPointsReturnsFalseWhenInsufficient(): void
|
|
{
|
|
$customerModel = $this->getMockBuilder(Customer::class)
|
|
->onlyMethods(['get_info'])
|
|
->getMock();
|
|
|
|
$customerModel->method('get_info')
|
|
->willReturn((object)['points' => 30]);
|
|
|
|
$reflection = new \ReflectionClass($this->rewardLib);
|
|
$property = $reflection->getProperty('customer');
|
|
$property->setAccessible(true);
|
|
$property->setValue($this->rewardLib, $customerModel);
|
|
|
|
$this->assertFalse($this->rewardLib->hasSufficientPoints(1, 50));
|
|
}
|
|
|
|
/**
|
|
* Test getPointsBalance returns correct balance
|
|
*/
|
|
public function testGetPointsBalanceReturnsCorrectValue(): void
|
|
{
|
|
$customerModel = $this->getMockBuilder(Customer::class)
|
|
->onlyMethods(['get_info'])
|
|
->getMock();
|
|
|
|
$customerModel->method('get_info')
|
|
->willReturn((object)['points' => 250]);
|
|
|
|
$reflection = new \ReflectionClass($this->rewardLib);
|
|
$property = $reflection->getProperty('customer');
|
|
$property->setAccessible(true);
|
|
$property->setValue($this->rewardLib, $customerModel);
|
|
|
|
$this->assertEquals(250, $this->rewardLib->getPointsBalance(1));
|
|
}
|
|
|
|
/**
|
|
* Test calculateRewardPaymentAmount with mixed payments
|
|
*/
|
|
public function testCalculateRewardPaymentAmountWithMixedPayments(): void
|
|
{
|
|
$payments = [
|
|
['payment_type' => 'Cash', 'payment_amount' => 50],
|
|
['payment_type' => 'Rewards', 'payment_amount' => 25],
|
|
['payment_type' => 'Credit Card', 'payment_amount' => 100],
|
|
['payment_type' => 'Rewards', 'payment_amount' => 15],
|
|
];
|
|
|
|
$rewardLabels = ['Rewards', 'Points'];
|
|
|
|
$total = $this->rewardLib->calculateRewardPaymentAmount($payments, $rewardLabels);
|
|
|
|
$this->assertEquals(40.0, $total);
|
|
}
|
|
|
|
/**
|
|
* Test calculateRewardPaymentAmount with empty payments
|
|
*/
|
|
public function testCalculateRewardPaymentAmountWithEmptyPayments(): void
|
|
{
|
|
$total = $this->rewardLib->calculateRewardPaymentAmount([], ['Rewards']);
|
|
$this->assertEquals(0.0, $total);
|
|
}
|
|
|
|
/**
|
|
* Test calculateRewardPaymentAmount with no matching labels
|
|
*/
|
|
public function testCalculateRewardPaymentAmountWithNoMatchingLabels(): void
|
|
{
|
|
$payments = [
|
|
['payment_type' => 'Cash', 'payment_amount' => 50],
|
|
['payment_type' => 'Credit Card', 'payment_amount' => 100],
|
|
];
|
|
|
|
$total = $this->rewardLib->calculateRewardPaymentAmount($payments, ['Rewards']);
|
|
$this->assertEquals(0.0, $total);
|
|
}
|
|
|
|
/**
|
|
* Test adjustRewardPoints returns false for null customer
|
|
*/
|
|
public function testAdjustRewardPointsReturnsFalseForNullCustomer(): void
|
|
{
|
|
$result = $this->rewardLib->adjustRewardPoints(null, 50, 'deduct');
|
|
$this->assertFalse($result);
|
|
}
|
|
|
|
/**
|
|
* Test adjustRewardPoints returns false for zero amount
|
|
*/
|
|
public function testAdjustRewardPointsReturnsFalseForZeroAmount(): void
|
|
{
|
|
$result = $this->rewardLib->adjustRewardPoints(1, 0, 'deduct');
|
|
$this->assertFalse($result);
|
|
}
|
|
|
|
/**
|
|
* Test adjustRewardDelta returns false for null customer
|
|
*/
|
|
public function testAdjustRewardDeltaReturnsFalseForNullCustomer(): void
|
|
{
|
|
$result = $this->rewardLib->adjustRewardDelta(null, 50);
|
|
$this->assertFalse($result);
|
|
}
|
|
|
|
/**
|
|
* Test adjustRewardDelta returns false for zero adjustment
|
|
*/
|
|
public function testAdjustRewardDeltaReturnsFalseForZeroAdjustment(): void
|
|
{
|
|
$result = $this->rewardLib->adjustRewardDelta(1, 0);
|
|
$this->assertFalse($result);
|
|
}
|
|
|
|
/**
|
|
* Test handleCustomerChange with same customer returns empty result
|
|
*/
|
|
public function testHandleCustomerChangeWithSameCustomerReturnsEmpty(): void
|
|
{
|
|
$result = $this->rewardLib->handleCustomerChange(1, 1, 50.0, 75.0);
|
|
$this->assertEquals(['restored' => 0.0, 'charged' => 0.0], $result);
|
|
}
|
|
|
|
/**
|
|
* Test handleCustomerChange with null customers
|
|
*/
|
|
public function testHandleCustomerChangeWithNullCustomers(): void
|
|
{
|
|
$result = $this->rewardLib->handleCustomerChange(null, null, 50.0, 75.0);
|
|
$this->assertEquals(['restored' => 0.0, 'charged' => 0.0], $result);
|
|
}
|
|
|
|
/**
|
|
* Test handleCustomerChange when customer changes from null to valid customer
|
|
*/
|
|
public function testHandleCustomerChangeFromNullToValidCustomer(): void
|
|
{
|
|
$customerModel = $this->getMockBuilder(Customer::class)
|
|
->onlyMethods(['get_info', 'update_reward_points_value'])
|
|
->getMock();
|
|
|
|
$customerModel->method('get_info')
|
|
->willReturn((object)['points' => 100]);
|
|
|
|
$customerModel->method('update_reward_points_value')
|
|
->willReturn(true);
|
|
|
|
$reflection = new \ReflectionClass($this->rewardLib);
|
|
$property = $reflection->getProperty('customer');
|
|
$property->setAccessible(true);
|
|
$property->setValue($this->rewardLib, $customerModel);
|
|
|
|
$result = $this->rewardLib->handleCustomerChange(null, 2, 0, 50.0);
|
|
|
|
$this->assertEquals(50.0, $result['charged']);
|
|
$this->assertEquals(0.0, $result['restored']);
|
|
}
|
|
|
|
/**
|
|
* Test update reward points correctly deducts from balance
|
|
*/
|
|
public function testPointsUpdateDuringSaleCreation(): void
|
|
{
|
|
$customerModel = $this->getMockBuilder(Customer::class)
|
|
->onlyMethods(['get_info', 'update_reward_points_value'])
|
|
->getMock();
|
|
|
|
$customerModel->method('get_info')
|
|
->willReturn((object)['points' => 200]);
|
|
|
|
$customerModel->expects($this->once())
|
|
->method('update_reward_points_value')
|
|
->with(1, 150);
|
|
|
|
$reflection = new \ReflectionClass($this->rewardLib);
|
|
$property = $reflection->getProperty('customer');
|
|
$property->setAccessible(true);
|
|
$property->setValue($this->rewardLib, $customerModel);
|
|
|
|
$this->rewardLib->adjustRewardPoints(1, 50, 'deduct');
|
|
}
|
|
|
|
/**
|
|
* Test update reward points correctly restores on sale deletion
|
|
*/
|
|
public function testPointsRestoreOnSaleDeletion(): void
|
|
{
|
|
$customerModel = $this->getMockBuilder(Customer::class)
|
|
->onlyMethods(['get_info', 'update_reward_points_value'])
|
|
->getMock();
|
|
|
|
$customerModel->method('get_info')
|
|
->willReturn((object)['points' => 150]);
|
|
|
|
$customerModel->expects($this->once())
|
|
->method('update_reward_points_value')
|
|
->with(1, 200);
|
|
|
|
$reflection = new \ReflectionClass($this->rewardLib);
|
|
$property = $reflection->getProperty('customer');
|
|
$property->setAccessible(true);
|
|
$property->setValue($this->rewardLib, $customerModel);
|
|
|
|
$this->rewardLib->adjustRewardPoints(1, 50, 'restore');
|
|
}
|
|
} |