Skip to content

Commit

Permalink
Merge pull request #78 from SamuelMwangiW/data-bundles
Browse files Browse the repository at this point in the history
Data Bundles
  • Loading branch information
SamuelMwangiW authored Aug 2, 2023
2 parents d09678a + e99cc6f commit 9a2aa89
Show file tree
Hide file tree
Showing 16 changed files with 511 additions and 5 deletions.
11 changes: 11 additions & 0 deletions src/Africastalking.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use SamuelMwangiW\Africastalking\Domain\Airtime;
use SamuelMwangiW\Africastalking\Domain\Application;
use SamuelMwangiW\Africastalking\Domain\MobileData;
use SamuelMwangiW\Africastalking\Domain\Payment;
use SamuelMwangiW\Africastalking\Domain\Stash;
use SamuelMwangiW\Africastalking\Domain\Voice;
Expand Down Expand Up @@ -35,6 +36,16 @@ public function payment(): Payment
return app(Payment::class);
}

public function bundles(): MobileData
{
return $this->mobileData();
}

public function mobileData(): MobileData
{
return app(MobileData::class);
}

public function sms(?string $message = null): Message
{
return app(Message::class)->text($message);
Expand Down
80 changes: 80 additions & 0 deletions src/Domain/MobileData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php

declare(strict_types=1);

namespace SamuelMwangiW\Africastalking\Domain;

use Illuminate\Support\Collection;
use SamuelMwangiW\Africastalking\Concerns\HasIdempotency;
use SamuelMwangiW\Africastalking\Enum\BundlesUnit;
use SamuelMwangiW\Africastalking\Enum\BundlesValidity;
use SamuelMwangiW\Africastalking\Saloon\Requests\MobileData\SendRequest;
use SamuelMwangiW\Africastalking\ValueObjects\DataBundlesResponse;
use SamuelMwangiW\Africastalking\ValueObjects\MobileDataTransaction;
use SamuelMwangiW\Africastalking\ValueObjects\PhoneNumber;

class MobileData
{
use HasIdempotency;

/** @var Collection<int,MobileDataTransaction> $recipients */
public Collection $recipients;

public string $productName;

public function __construct()
{
$this->recipients = collect([]);
$this->productName = config('africastalking.payment.product-name');
}

public function productName(string $name): MobileData
{
$this->productName = $name;

return $this;
}

public function to(
PhoneNumber|string $phoneNumber,
int $quantity,
BundlesValidity $validity,
BundlesUnit $unit = BundlesUnit::MB,
bool $isPromoBundle = false,
array $meta = [],
): MobileData {
if (is_string($phoneNumber)) {
$phoneNumber = PhoneNumber::make($phoneNumber);
}

$transaction = MobileDataTransaction::make(
phoneNumber: $phoneNumber,
quantity: $quantity,
validity: $validity,
unit: $unit,
isPromoBundle: $isPromoBundle,
meta: $meta,
);

$this->recipients->push($transaction);

return $this;
}

public function send(): DataBundlesResponse
{
$request = SendRequest::make(
productName: $this->productName,
recipients: $this->recipients
->map(
fn (MobileDataTransaction $transaction) => $transaction->toArray()
)->toArray(),
);

if ($this->idempotencyKey()) {
$request->headers()->add('Idempotency-Key', $this->idempotencyKey());
}

return $request->send()->throw()->dto();
}
}
11 changes: 11 additions & 0 deletions src/Enum/BundlesUnit.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace SamuelMwangiW\Africastalking\Enum;

enum BundlesUnit: string
{
case MB = 'MB';
case GB = 'GB';
}
14 changes: 14 additions & 0 deletions src/Enum/BundlesValidity.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace SamuelMwangiW\Africastalking\Enum;

enum BundlesValidity: string
{
case DAILY = 'Day';
case WEEKLY = 'Week';
case BI_WEEKLY = 'BiWeekly';
case MONTHLY = 'Month';
case QUARTERLY = 'Quarterly';
}
4 changes: 2 additions & 2 deletions src/Enum/Service.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public function liveBaseUrl(): string
self::APPLICATION,
self::BULK_SMS => 'https://api.africastalking.com/version1/',
self::CONTENT => 'https://content.africastalking.com/version1/',
self::DATA,
self::DATA => 'https://bundles.africastalking.com/',
self::PAYMENT => 'https://payments.africastalking.com/',
self::VOICE => 'https://voice.africastalking.com/',
self::WEBRTC => 'https://webrtc.africastalking.com',
Expand All @@ -43,7 +43,7 @@ public function sandboxBaseUrl(): string
self::CONTENT => 'https://api.sandbox.africastalking.com/version1/',
self::PAYMENT => 'https://payments.sandbox.africastalking.com/',
self::VOICE => 'https://voice.sandbox.africastalking.com/',
self::DATA => throw new Exception('Mobile data is not supported on Sandbox'),
self::DATA => 'https://bundles.sandbox.africastalking.com/',
self::WEBRTC => throw new Exception('WebRTC not supported on Sandbox environment'),
};
}
Expand Down
1 change: 1 addition & 0 deletions src/Enum/Status.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ enum Status: string
case REJECTED = 'Rejected';
case SUCCESS = 'Success';
case FAILED = 'Failed';
case QUEUED = 'Queued';
case SENT = 'Sent';
}
6 changes: 5 additions & 1 deletion src/Http/Requests/VoiceEventRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public function rules(): array
'callerCountryCode' => ['nullable', 'string', 'max:4'],
'callStartTime' => ['nullable', 'string'],
'recordingUrl' => ['nullable', 'url'],
'durationInSeconds ' => ['nullable', 'int', 'min:0'],
'durationInSeconds' => ['nullable', 'int', 'min:0'],
'currencyCode' => ['nullable', 'string', new Enum(Currency::class)],
'amount' => ['nullable', 'numeric'],
'dialDestinationNumber' => ['nullable', 'string'],
Expand All @@ -60,6 +60,10 @@ public function downloadRecording(string|null $disk = null, string|null $path =
return;
}

if (0 === $this->integer('durationInSeconds')) {
return;
}

DownloadCallRecording::dispatch(
$this->input('recordingUrl'),
$this->id(),
Expand Down
44 changes: 44 additions & 0 deletions src/Saloon/Requests/MobileData/SendRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace SamuelMwangiW\Africastalking\Saloon\Requests\MobileData;

use Saloon\Contracts\Body\HasBody;
use Saloon\Contracts\Response;
use Saloon\Traits\Body\HasJsonBody;
use SamuelMwangiW\Africastalking\Enum\Service;
use SamuelMwangiW\Africastalking\Saloon\Requests\BaseRequest;
use SamuelMwangiW\Africastalking\ValueObjects\DataBundlesResponse;

class SendRequest extends BaseRequest implements HasBody
{
use HasJsonBody;

public Service $service = Service::DATA;

public function __construct(
private readonly string $productName,
private readonly array $recipients,
) {
}

public function resolveEndpoint(): string
{
return 'mobile/data/request';
}

public function defaultBody(): array
{
return [
'username' => $this->username(),
'productName' => $this->productName,
'recipients' => $this->recipients,
];
}

public function createDtoFromResponse(Response $response): DataBundlesResponse
{
return DataBundlesResponse::fromResponse($response);
}
}
45 changes: 45 additions & 0 deletions src/ValueObjects/DataBundlesResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

namespace SamuelMwangiW\Africastalking\ValueObjects;

use Illuminate\Support\Collection;
use Saloon\Contracts\Response;
use SamuelMwangiW\Africastalking\Enum\Status;

class DataBundlesResponse implements \SamuelMwangiW\Africastalking\Contracts\DTOContract
{
public function __construct(
/** @var Collection<int,DataBundlesResponseEntry> $entries */
public readonly Collection $entries
) {
}

public static function fromResponse(Response $response): DataBundlesResponse
{
$entries = $response
->collect('entries')
->map(function (array $entry) {
return new DataBundlesResponseEntry(
number: PhoneNumber::make(data_get($entry, 'phoneNumber')),
provider: data_get($entry, 'provider'),
status: Status::from(data_get($entry, 'status')),
transactionId: data_get($entry, 'transactionId'),
value: Money::make(data_get($entry, 'value'))
);
});

return new DataBundlesResponse(entries: $entries);
}

public function __toString(): string
{
return (string) json_encode($this);
}

public function __toArray(): array
{
return [];
}
}
30 changes: 30 additions & 0 deletions src/ValueObjects/DataBundlesResponseEntry.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace SamuelMwangiW\Africastalking\ValueObjects;

use SamuelMwangiW\Africastalking\Contracts\DTOContract;
use SamuelMwangiW\Africastalking\Enum\Status;

class DataBundlesResponseEntry implements DTOContract
{
public function __construct(
public readonly PhoneNumber $number,
public readonly string $provider,
public readonly Status $status,
public readonly string $transactionId,
public readonly Money $value
) {
}

public function __toString(): string
{
return (string) json_encode($this);
}

public function __toArray(): array
{
return [];
}
}
51 changes: 51 additions & 0 deletions src/ValueObjects/MobileDataTransaction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

declare(strict_types=1);

namespace SamuelMwangiW\Africastalking\ValueObjects;

use SamuelMwangiW\Africastalking\Enum\BundlesUnit;
use SamuelMwangiW\Africastalking\Enum\BundlesValidity;

class MobileDataTransaction
{
public function __construct(
public readonly PhoneNumber $phoneNumber,
public readonly int $quantity,
public readonly BundlesValidity $validity,
public readonly BundlesUnit $unit = BundlesUnit::MB,
public readonly bool $isPromoBundle = false,
public readonly array $meta = [],
) {
}

public static function make(
PhoneNumber $phoneNumber,
int $quantity,
BundlesValidity $validity,
BundlesUnit $unit = BundlesUnit::MB,
bool $isPromoBundle = false,
array $meta = [],
): MobileDataTransaction {
return new MobileDataTransaction(
phoneNumber: $phoneNumber,
quantity: $quantity,
validity: $validity,
unit: $unit,
isPromoBundle: $isPromoBundle,
meta: $meta
);
}

public function toArray(): array
{
return [
'phoneNumber' => $this->phoneNumber->number,
'quantity' => $this->quantity,
'unit' => $this->unit->value,
'validity' => $this->validity->value,
'isPromoBundle' => $this->isPromoBundle,
'metadata' => (object) $this->meta,
];
}
}
10 changes: 10 additions & 0 deletions src/ValueObjects/Money.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ public function __construct(
) {
}

public static function make(string $value): Money
{
$parts = explode(' ', $value);

return new Money(
amount: floatval($parts[1]),
currency: Currency::from($parts[0])
);
}

public function __toString(): string
{
return "{$this->currency->value} {$this->amount}";
Expand Down
Loading

0 comments on commit 9a2aa89

Please sign in to comment.