Deploy Ladill POS / deploy (push) Has been cancelled
Redeem at charge, earn on payment, reverse on cancel, and surface balances on the till, customer display, sales, and receipts.
169 lines
4.8 KiB
PHP
169 lines
4.8 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Crm;
|
|
|
|
use Illuminate\Http\Client\ConnectionException;
|
|
use Illuminate\Http\Client\PendingRequest;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
class CrmClient
|
|
{
|
|
public function __construct(private readonly string $owner) {}
|
|
|
|
public static function for(string $owner): self
|
|
{
|
|
return new self($owner);
|
|
}
|
|
|
|
public function customers(array $filters = []): array
|
|
{
|
|
return $this->get('customers', $filters);
|
|
}
|
|
|
|
public function products(array $filters = []): array
|
|
{
|
|
return $this->get('products', $filters);
|
|
}
|
|
|
|
public function product(int|string $id): array
|
|
{
|
|
return $this->get("products/{$id}");
|
|
}
|
|
|
|
public function createProduct(array $data): array
|
|
{
|
|
return $this->send('post', 'products', $data);
|
|
}
|
|
|
|
/**
|
|
* Bulk-create products (one CRM INSERT per call). Caller batches large
|
|
* catalogs; the CRM caps each request at 500 rows.
|
|
*
|
|
* @param array<int, array<string, mixed>> $products
|
|
*/
|
|
public function bulkCreateProducts(array $products): array
|
|
{
|
|
return $this->send('post', 'products/bulk', ['products' => array_values($products)]);
|
|
}
|
|
|
|
public function updateProduct(int|string $id, array $data): array
|
|
{
|
|
return $this->send('patch', "products/{$id}", $data);
|
|
}
|
|
|
|
public function deleteProduct(int|string $id): array
|
|
{
|
|
return $this->send('delete', "products/{$id}", []);
|
|
}
|
|
|
|
public function pushTimeline(array $data): array
|
|
{
|
|
return $this->post('timeline', $data);
|
|
}
|
|
|
|
/** @return array<string, mixed> */
|
|
public function loyaltyProgram(): array
|
|
{
|
|
return $this->get('loyalty/program');
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function customerLoyalty(int|string $customerId, ?int $amountMinor = null): array
|
|
{
|
|
$query = [];
|
|
if ($amountMinor !== null) {
|
|
$query['amount_minor'] = $amountMinor;
|
|
}
|
|
|
|
return $this->get("customers/{$customerId}/loyalty", $query);
|
|
}
|
|
|
|
/**
|
|
* @param array{customer_id: int, subtotal_minor: int, redeem_points?: int} $data
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function loyaltyQuote(array $data): array
|
|
{
|
|
return $this->post('loyalty/quote', $data);
|
|
}
|
|
|
|
/**
|
|
* @param array{customer_id: int, subtotal_minor: int, redeem_points: int, external_ref: string, source?: string, description?: string} $data
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function loyaltyRedeem(array $data): array
|
|
{
|
|
return $this->post('loyalty/redeem', $data);
|
|
}
|
|
|
|
/**
|
|
* @param array{customer_id: int, amount_minor: int, external_ref: string, source?: string, description?: string} $data
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function loyaltyEarn(array $data): array
|
|
{
|
|
return $this->post('loyalty/earn', $data);
|
|
}
|
|
|
|
/**
|
|
* @param array{external_ref: string, source?: string} $data
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function loyaltyReverse(array $data): array
|
|
{
|
|
return $this->post('loyalty/reverse', $data);
|
|
}
|
|
|
|
private function client(): PendingRequest
|
|
{
|
|
return Http::baseUrl((string) config('crm.url'))
|
|
->withToken((string) config('crm.key'))
|
|
->acceptJson()
|
|
->asJson()
|
|
->connectTimeout(10)
|
|
->timeout(20);
|
|
}
|
|
|
|
private function get(string $path, array $query = []): array
|
|
{
|
|
return $this->handle(fn () => $this->client()->get($path, [...$query, 'owner' => $this->owner]));
|
|
}
|
|
|
|
private function post(string $path, array $data): array
|
|
{
|
|
return $this->handle(fn () => $this->client()->post($path, [...$data, 'owner' => $this->owner]));
|
|
}
|
|
|
|
private function send(string $method, string $path, array $data): array
|
|
{
|
|
return $this->handle(fn () => $this->client()->{$method}($path, [...$data, 'owner' => $this->owner]));
|
|
}
|
|
|
|
private function handle(callable $request): array
|
|
{
|
|
try {
|
|
$response = $request();
|
|
} catch (ConnectionException) {
|
|
throw ValidationException::withMessages([
|
|
'crm' => ['Could not reach the CRM service. Please try again in a moment.'],
|
|
]);
|
|
}
|
|
|
|
if ($response->failed()) {
|
|
if ($response->status() === 422) {
|
|
$message = (string) ($response->json('message')
|
|
?? collect((array) $response->json('errors'))->flatten()->first()
|
|
?? 'CRM validation failed.');
|
|
throw ValidationException::withMessages(['crm' => [$message]]);
|
|
}
|
|
|
|
abort($response->status() === 404 ? 404 : 502, 'CRM service error.');
|
|
}
|
|
|
|
return (array) $response->json();
|
|
}
|
|
}
|