Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Single Product #193

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,24 @@ $whatsapp_cloud_api->sendButton(
);
```

### Send Single Product Message
```php
<?php

$catalog_id = '<catalog-id>';
$sku_id = '<product-sku-id>';
$body = 'Hello! Here\'s your requested product. Thanks for shopping with us.';
$footer = 'Subject to T&C';

$whatsapp_cloud_api->sendSingleProduct(
'<destination-phone-number>',
$catalog_id,
$sku_id,
$body, // body: optional
$footer // footer: optional
);
```

### Replying messages

You can reply a previous sent message:
Expand Down Expand Up @@ -410,6 +428,7 @@ Fields list: https://developers.facebook.com/docs/whatsapp/cloud-api/reference/b
- Send Contacts
- Send Lists
- Send Buttons
- Send Single Product
- Upload media resources to WhatsApp servers
- Download media resources from WhatsApp servers
- Mark messages as read
Expand Down
52 changes: 52 additions & 0 deletions src/Message/SingleProductMessage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

namespace Netflie\WhatsAppCloudApi\Message;

final class SingleProductMessage extends Message
{
/**
* {@inheritdoc}
*/
protected string $type = 'product';

private int $catalog_id;

private string $product_retailer_id;

private ?string $body;

private ?string $footer;

/**
* {@inheritdoc}
*/
public function __construct(string $to, int $catalog_id, string $product_retailer_id, ?string $body, ?string $footer, ?string $reply_to)
{
$this->catalog_id = $catalog_id;
$this->product_retailer_id = $product_retailer_id;
$this->body = $body;
$this->footer = $footer;

parent::__construct($to, $reply_to);
}

public function catalog_id(): int
{
return $this->catalog_id;
}

public function product_retailer_id(): string
{
return $this->product_retailer_id;
}

public function body(): ?string
{
return $this->body;
}

public function footer(): ?string
{
return $this->footer;
}
}
42 changes: 42 additions & 0 deletions src/Request/MessageRequest/RequestSingleProductMessage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace Netflie\WhatsAppCloudApi\Request\MessageRequest;

use Netflie\WhatsAppCloudApi\Request\MessageRequest;

final class RequestSingleProductMessage extends MessageRequest
{
/**
* {@inheritdoc}
*/
public function body(): array
{
$body = [
'messaging_product' => $this->message->messagingProduct(),
'recipient_type' => $this->message->recipientType(),
'to' => $this->message->to(),
'type' => 'interactive',
'interactive' => [
'type' => $this->message->type(),
'action' => [
'catalog_id' => $this->message->catalog_id(),
'product_retailer_id' => $this->message->product_retailer_id(),
],
],
];

if ($this->message->body()) {
$body['interactive']['body'] = ['text' => $this->message->body()];
}

if ($this->message->footer()) {
$body['interactive']['footer'] = ['text' => $this->message->footer()];
}

if ($this->message->replyTo()) {
$body['context']['message_id'] = $this->message->replyTo();
}

return $body;
}
}
26 changes: 26 additions & 0 deletions src/WhatsAppCloudApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,32 @@ public function markMessageAsRead(string $message_id): Response
return $this->client->sendMessage($request);
}

/**
* Sends a single product message to a specified recipient.
*
* @param string $to The WhatsApp ID or phone number for the person you want to send the message to.
* @param int $catalog_id The ID of the catalog where the product is located.
* @param string $product_retailer_id The retailer-specific ID of the product.
* @param string|null $body The body of the message. Defaults to an empty string if not provided.
* @param string|null $footer The footer of the message. Defaults to an empty string if not provided.
*
* @return Response The response object containing the result of the API request.
*
* @throws Response\ResponseException If there is an error with the API request.
*/
public function sendSingleProduct(string $to, int $catalog_id, string $product_retailer_id, ?string $body = '', ?string $footer = '')
{
$message = new Message\SingleProductMessage($to, $catalog_id, $product_retailer_id, $body, $footer, $this->reply_to);
$request = new Request\MessageRequest\RequestSingleProductMessage(
$message,
$this->app->accessToken(),
$this->app->fromPhoneNumberId(),
$this->timeout
);

return $this->client->sendMessage($request);
}

/**
* Get Business Profile
*
Expand Down
23 changes: 23 additions & 0 deletions tests/Integration/WhatsAppCloudApiTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,29 @@ public function test_send_reply_buttons()
$this->assertEquals(false, $response->isError());
}

public function test_send_single_product()
{
$this->markTestIncomplete(
'This test requires real catalog id and product sku id.'
);

$catalog_id = '<catalog-id>';
$sku_id = '<product-sku-id>';
$body = 'Hello! Here\'s your requested product. Thanks for shopping with us.';
$footer = 'Subject to T&C';

$response = $this->whatsapp_app_cloud_api->sendSingleProduct(
WhatsAppCloudApiTestConfiguration::$to_phone_number_id,
$catalog_id,
$sku_id,
$body, // body: optional
$footer // footer: optional
);

$this->assertEquals(200, $response->httpStatusCode());
$this->assertEquals(false, $response->isError());
}

public function test_upload_media()
{
$response = $this->whatsapp_app_cloud_api->uploadMedia('tests/Support/netflie.png');
Expand Down
47 changes: 47 additions & 0 deletions tests/Unit/WhatsAppCloudApiTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1145,6 +1145,53 @@ public function test_update_business_profile()
$this->assertEquals(false, $response->isError());
}

public function test_send_single_product()
{
$to = $this->faker->phoneNumber;
$url = $this->buildMessageRequestUri();
$message = $this->faker->text(1024);
$footer = $this->faker->text(60);
$catalog_id = $this->faker->randomNumber();
$product_retailer_id = $this->faker->uuid();

$body = [
'messaging_product' => 'whatsapp',
'recipient_type' => 'individual',
'to' => $to,
'type' => 'interactive',
'interactive' => [
'type' => 'product',
'body' => ['text' => $message],
'footer' => ['text' => $footer],
'action' => [
'catalog_id' => $catalog_id,
'product_retailer_id' => $product_retailer_id,
],
],
];
$headers = [
'Authorization' => 'Bearer ' . $this->access_token,
];

$this->client_handler
->postJsonData($url, $body, $headers, Argument::type('int'))
->shouldBeCalled()
->willReturn(new RawResponse($headers, $this->successfulMessageNodeResponse(), 200));

$response = $this->whatsapp_app_cloud_api->sendSingleProduct(
$to,
$catalog_id,
$product_retailer_id,
$message,
$footer
);

$this->assertEquals(200, $response->httpStatusCode());
$this->assertEquals(json_decode($this->successfulMessageNodeResponse(), true), $response->decodedBody());
$this->assertEquals($this->successfulMessageNodeResponse(), $response->body());
$this->assertEquals(false, $response->isError());
}

public function test_mark_a_message_as_read()
{
$url = $this->buildMessageRequestUri();
Expand Down