Skip to content

Instantly share code, notes, and snippets.

@voicecode-bv
Last active September 6, 2022 17:13
Show Gist options
  • Save voicecode-bv/0a97d04f923babe2ed22b0009e3beae8 to your computer and use it in GitHub Desktop.
Save voicecode-bv/0a97d04f923babe2ed22b0009e3beae8 to your computer and use it in GitHub Desktop.
Transfer domain and subscriptions to another Google reseller
<?php
namespace App\Http\Controllers\Customer\Contact\GoogleWorkspace;
use App\Http\Controllers\Controller;
use App\Http\Requests\Customer\GoogleWorkspace\Transfers\TransferSubscriptionsRequest;
use App\Models\Contact;
use App\Services\GoogleSubscriptionService;
use Google\Service\Exception;
class TransferDomainsController extends Controller
{
/**
* Show list of transferable subscriptions.
*
* @param TransferSubscriptionsRequest $request
* @param Contact $contact
* @param string $domain
* @param string $token Encrypted token value.
* @return void
*/
public function transferSubscriptions(TransferSubscriptionsRequest $request, Contact $contact, string $domain, string $token)
{
// Fetch subscription details.
$hasException = false;
$google = new GoogleSubscriptionService();
$subscriptions = $google->getSubscriptionsByDomain($domain, decrypt($token));
// Transfer subscriptions.
// This is where it breaks, continue with GoogleSubscriptionService.php.
$response = $google->transferSubscriptions($domain, $subscriptions, decrypt($token));
// ....
}
}
<?php
use Google\Service\Reseller;
use Throwable;
class GoogleSubscriptionService
{
private $client;
public function __construct()
{
$this->setupClient();
}
/**
* Setup Google Client
*
* @return void
*/
private function setupClient()
{
$google_client = new Client();
$google_client->setApplicationName('App Name');
putenv('GOOGLE_APPLICATION_CREDENTIALS='.base_path().'/google_client.json');
$google_client->useApplicationDefaultCredentials();
$google_client->setScopes([Reseller::APPS_ORDER]);
$google_client->setSubject('user@domain.com');
$this->client = $google_client;
}
/**
* Get subscriptions by domain
*
* @param string $domain
* @param string $token
*/
public function getSubscriptionsByDomain($domain, $token)
{
try {
$google = new Reseller($this->client);
$data = $google->subscriptions->listSubscriptions([
'customerId' => $domain,
'customerAuthToken' => $token,
])->getSubscriptions();
return $data;
} catch (Throwable $e) {
return $e;
}
}
/**
* Transfer subscriptions via a batch request.
*
* @param string $domain
* @param array $subscriptions
* @param string $token
*/
public function transferSubscriptions(string $domain, array $subscriptions, string $token)
{
// Make sure to activate batch requests.
$this->client->setUseBatch(true);
try {
$google = new Reseller($this->client);
$batch = $google->createBatch();
// Iterate subscriptions and add request to batch.
foreach ($subscriptions as $subscription) {
// Build request.
$request = $google->subscriptions->insert($domain, $subscription, [
'customerAuthToken' => $token,
]);
// Add request to batch.
$batch->add($request);
}
// Execute batch.
return $batch->execute();
} catch (Throwable $e) {
return $e;
}
}
}
// Request data as generated by the PHP Google API library
// Google\Http\Batch, logged this info on rule 131
array:4 [▼
"method" => "POST"
"url" => "https://reseller.googleapis.com/batch"
"headers" => array:2 [▼
"Content-Type" => "multipart/mixed; boundary=904299535"
"Content-Length" => "1006"
]
"body" => """
--904299535
Content-Type: application/http
Content-Transfer-Encoding: binary
MIME-Version: 1.0
Content-ID: 1492737493
POST /apps/reseller/v1/customers/######/subscriptions?customerAuthToken=####### HTTP/1.1
Host:reseller.googleapis.com
content-type:application/json
X-Php-Expected-Class:Google\Service\Reseller\Subscription
{"billingMethod":"ONLINE","creationTime":"1661351293638","customerDomain":"######","customerId":"######","kind":"reseller#subscription","resourceUiUrl":"https:\/\/admin.google.com\/ac\/billing\/subscriptions?ecid=######","skuId":"1010020027","skuName":"Google Workspace Business Starter","status":"ACTIVE","subscriptionId":"4321824362","seats":{"kind":"subscriptions#seats","licensedNumberOfSeats":1,"maximumNumberOfSeats":1},"plan":{"isCommitmentPlan":false,"planName":"TRIAL"},"trialSettings":{"isInTrial":true,"trialEndTime":"1663943293625"},"transferInfo":{"minimumTransferableSeats":1,"transferabilityExpirationTime":"1662560942807"}}
--904299535--
"""
]
array:1 [▼
"response-1492737493" => Google\Service\Exception {#1779 ▼
#message: """
{
"error": {
"code": 400,
"message": "Licensed number of seats field is read-only",
"errors": [
{
"message": "Licensed number of seats field is read-only",
"domain": "global",
"reason": "invalid"
}
]
}
}
"""
#code: 400
#file: "/Users/#####/Desktop/Development/app/vendor/google/apiclient/src/Http/REST.php"
#line: 130
#errors: array:1 [▼
0 => array:3 [▼
"message" => "Licensed number of seats field is read-only"
"domain" => "global"
"reason" => "invalid"
]
]
trace: {▼
/Users/######/Desktop/Development/app/vendor/google/apiclient/src/Http/REST.php:130 {▼
Google\Http\REST::decodeHttpResponse(ResponseInterface $response, RequestInterface $request = null, $expectedClass = null) …
› // Check if we received errors, and add those to the Exception for convenience
› throw new GoogleServiceException($body, $code, null, self::getResponseErrors($body));
› }
}
...
}
}
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment