128 lines
4.4 KiB
PHP
128 lines
4.4 KiB
PHP
<?php
|
|
|
|
use App\Models\BillingItemType;
|
|
use App\Models\Client;
|
|
use App\Models\ClientInvoice;
|
|
use App\Models\ClientInvoicePayment;
|
|
use App\Models\ClientInvoicePaymentItem;
|
|
use App\Services\GoogleAdsService;
|
|
use Illuminate\Support\Carbon;
|
|
|
|
function createInvoiceItem(
|
|
Client $client,
|
|
int $billingItemTypeId,
|
|
?string $startDate,
|
|
?string $endDate,
|
|
float $spending = 0,
|
|
): ClientInvoicePaymentItem {
|
|
$invoice = ClientInvoice::query()->forceCreate([
|
|
'client_id' => $client->id,
|
|
'invoice_no' => fake()->unique()->numerify('INV-####'),
|
|
]);
|
|
|
|
$payment = ClientInvoicePayment::query()->create([
|
|
'client_invoice_id' => $invoice->id,
|
|
]);
|
|
|
|
return ClientInvoicePaymentItem::query()->create([
|
|
'client_invoice_payment_id' => $payment->id,
|
|
'billing_item_types_id' => $billingItemTypeId,
|
|
'start_date' => $startDate,
|
|
'end_date' => $endDate,
|
|
'spending' => $spending,
|
|
]);
|
|
}
|
|
|
|
test('it updates every eligible invoice payment item for each client', function () {
|
|
Carbon::setTestNow('2026-06-25 10:00:00');
|
|
|
|
BillingItemType::query()->insert([
|
|
['id' => 1, 'name' => 'Media'],
|
|
['id' => 2, 'name' => 'Management'],
|
|
]);
|
|
|
|
$firstClient = Client::factory()->create([
|
|
'customer_id' => '1111111111',
|
|
'status' => 'ENABLED',
|
|
'time_zone' => 'Asia/Kuala_Lumpur',
|
|
]);
|
|
$secondClient = Client::factory()->create([
|
|
'customer_id' => '2222222222',
|
|
'status' => 'ENABLED',
|
|
'time_zone' => 'Asia/Kuala_Lumpur',
|
|
]);
|
|
|
|
$olderItem = createInvoiceItem($firstClient, 1, '2026-05-01', '2026-05-31', 10);
|
|
$latestItem = createInvoiceItem($firstClient, 1, '2026-06-01', null);
|
|
$otherTypeItem = createInvoiceItem($firstClient, 2, '2026-06-01', null, 20);
|
|
$secondClientItem = createInvoiceItem($secondClient, 1, '2026-06-10', '2026-06-20');
|
|
|
|
$adsService = Mockery::mock(GoogleAdsService::class);
|
|
$adsService->shouldReceive('listCampaigns')
|
|
->twice()
|
|
->with('1111111111')
|
|
->andReturn([['id' => 101], ['id' => 102]]);
|
|
$adsService->shouldReceive('listCampaignsMetricsById')
|
|
->once()
|
|
->with('1111111111', '101', '2026-05-01', '2026-05-31')
|
|
->andReturn([['actual_spend' => 3.25]]);
|
|
$adsService->shouldReceive('listCampaignsMetricsById')
|
|
->once()
|
|
->with('1111111111', '102', '2026-05-01', '2026-05-31')
|
|
->andReturn([['actual_spend' => 4.75]]);
|
|
$adsService->shouldReceive('listCampaignsMetricsById')
|
|
->once()
|
|
->with('1111111111', '101', '2026-06-01', '2026-06-25')
|
|
->andReturn([['actual_spend' => 12.25]]);
|
|
$adsService->shouldReceive('listCampaignsMetricsById')
|
|
->once()
|
|
->with('1111111111', '102', '2026-06-01', '2026-06-25')
|
|
->andReturn([['actual_spend' => 7.75]]);
|
|
$adsService->shouldReceive('listCampaigns')
|
|
->once()
|
|
->with('2222222222')
|
|
->andReturn([['id' => 201]]);
|
|
$adsService->shouldReceive('listCampaignsMetricsById')
|
|
->once()
|
|
->with('2222222222', '201', '2026-06-10', '2026-06-20')
|
|
->andReturn([['actual_spend' => 5.5]]);
|
|
|
|
app()->instance(GoogleAdsService::class, $adsService);
|
|
|
|
$this->artisan('customer:update-latest-invoice-item-spending')
|
|
->expectsOutputToContain('Done. 3 calculated, 0 skipped, 0 failed.')
|
|
->assertSuccessful();
|
|
|
|
expect((float) $olderItem->fresh()->spending)->toBe(8.0)
|
|
->and((float) $latestItem->fresh()->spending)->toBe(20.0)
|
|
->and((float) $otherTypeItem->fresh()->spending)->toBe(20.0)
|
|
->and((float) $secondClientItem->fresh()->spending)->toBe(5.5);
|
|
});
|
|
|
|
test('dry run calculates spending without updating the item', function () {
|
|
BillingItemType::query()->insert([
|
|
'id' => 1,
|
|
'name' => 'Media',
|
|
]);
|
|
|
|
$client = Client::factory()->create([
|
|
'customer_id' => '3333333333',
|
|
'status' => 'ENABLED',
|
|
'time_zone' => 'Asia/Kuala_Lumpur',
|
|
]);
|
|
$item = createInvoiceItem($client, 1, '2026-06-01', '2026-06-15', 8);
|
|
|
|
$adsService = Mockery::mock(GoogleAdsService::class);
|
|
$adsService->shouldReceive('listCampaigns')
|
|
->once()
|
|
->with('3333333333')
|
|
->andReturn([]);
|
|
|
|
app()->instance(GoogleAdsService::class, $adsService);
|
|
|
|
$this->artisan('customer:update-latest-invoice-item-spending', ['--dry-run' => true])
|
|
->assertSuccessful();
|
|
|
|
expect((float) $item->fresh()->spending)->toBe(8.0);
|
|
});
|