Files
isaaccladandCursor e251a4cf60
Deploy Ladill Hosting / deploy (push) Failing after 17s
Initial Ladill Hosting app with Gitea deploy pipeline.
Shared web hosting extracted from the platform monolith, with CI deploy
to /var/www/ladill-hosting matching Bird/Domains/Email.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-06 16:24:20 +00:00

276 lines
10 KiB
PHP

<?php
namespace App\Services\ResellerClub;
use App\Models\RcServiceOrder;
use App\Services\Domain\DomainRegistrarService;
use App\Support\ResellerClubLegacy;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Crypt;
class RcOrderFulfillmentService
{
public function __construct(
private readonly ResellerClubCustomerService $customers,
private readonly ResellerClubProductService $products,
private readonly DomainRegistrarService $registrar,
) {
}
public function processPaidOrder(int|RcServiceOrder $order): void
{
$order = $order instanceof RcServiceOrder
? $order->fresh(['user'])
: RcServiceOrder::query()->with('user')->find($order);
if (! $order || $order->payment_status !== RcServiceOrder::PAYMENT_STATUS_PAID) {
return;
}
if (in_array($order->fulfillment_status, [RcServiceOrder::FULFILLMENT_SUBMITTING, RcServiceOrder::FULFILLMENT_FULFILLED], true)) {
return;
}
if (! ResellerClubLegacy::canAutomateFulfillment($order)) {
$message = ResellerClubLegacy::isRenewalRcServiceOrder($order)
? ResellerClubLegacy::renewalsDisabledMessage()
: ResellerClubLegacy::fulfillmentDisabledMessage();
$this->markManualReview($order, $message);
return;
}
$order->forceFill([
'status' => RcServiceOrder::STATUS_PROCESSING,
'fulfillment_status' => RcServiceOrder::FULFILLMENT_SUBMITTING,
])->save();
$resolved = $this->customers->resolveCustomerForUser($order->user);
if (! ($resolved['success'] ?? false)) {
$this->markManualReview($order, $resolved['message'] ?? 'Could not prepare the ResellerClub customer.');
return;
}
$customerId = (string) ($resolved['customer_id'] ?? '');
match ($order->order_type) {
RcServiceOrder::TYPE_DOMAIN_REGISTRATION => $this->submitDomainRegistration($order, $customerId),
RcServiceOrder::TYPE_DOMAIN_TRANSFER => $this->submitDomainTransfer($order, $customerId),
RcServiceOrder::TYPE_RENEWAL => $this->submitRenewal($order, $customerId),
default => $this->submitServiceOrder($order, $customerId),
};
}
private function submitDomainRegistration(RcServiceOrder $order, string $customerId): void
{
$contact = $this->registrar->resolveContactForCustomer($order->user, $customerId);
if (! ($contact['success'] ?? false)) {
$this->markManualReview($order, $contact['message'] ?? 'Could not prepare the domain contact.');
return;
}
$registration = $this->registrar->registerDomain(
$order->domain_name,
max(1, (int) ($order->term_years ?: 1)),
$customerId,
(string) ($contact['contact_id'] ?? '')
);
if (! ($registration['success'] ?? false)) {
$this->markManualReview($order, $registration['message'] ?? 'The registrar did not accept the domain order.');
return;
}
$this->markAwaitingVendor($order, $customerId, (string) ($registration['order_id'] ?? ''));
}
private function submitDomainTransfer(RcServiceOrder $order, string $customerId): void
{
$contact = $this->registrar->resolveContactForCustomer($order->user, $customerId);
if (! ($contact['success'] ?? false)) {
$this->markManualReview($order, $contact['message'] ?? 'Could not prepare the domain contact.');
return;
}
$encryptedAuthCode = (string) Arr::get($order->meta ?? [], 'transfer_auth_code_encrypted', '');
$authCode = $encryptedAuthCode !== '' ? Crypt::decryptString($encryptedAuthCode) : null;
$transfer = $this->registrar->transferDomain(
$order->domain_name,
$authCode,
$customerId,
(string) ($contact['contact_id'] ?? '')
);
if (! ($transfer['success'] ?? false)) {
$this->markManualReview($order, $transfer['message'] ?? 'The registrar did not accept the transfer request.');
return;
}
$this->markAwaitingVendor($order, $customerId, (string) ($transfer['order_id'] ?? ''));
}
private function submitRenewal(RcServiceOrder $order, string $customerId): void
{
$rcOrderId = (string) data_get($order->meta, 'renew_rc_order_id', $order->rc_order_id ?? '');
if ($rcOrderId === '') {
$this->markManualReview($order, 'Renewal is missing the upstream ResellerClub order id.');
return;
}
if (in_array($order->category, ['domain-renewal', 'domain-registration', 'domain-transfer'], true)
&& $order->order_type === RcServiceOrder::TYPE_RENEWAL) {
$years = max(1, (int) ($order->term_years ?: 1));
$renewal = $this->registrar->renewDomain(
$order->domain_name,
$years,
$customerId
);
if (! ($renewal['success'] ?? false)) {
$this->markManualReview($order, $renewal['message'] ?? 'The registrar did not accept the domain renewal.');
return;
}
$this->markRenewalComplete($order, $customerId, (string) ($renewal['order_id'] ?? $rcOrderId));
return;
}
$months = max(1, (int) ($order->term_months ?: 1));
$renewal = $this->products->renewOrder($order->category, $rcOrderId, $months);
if (! ($renewal['success'] ?? false)) {
$this->markManualReview($order, $renewal['message'] ?? 'The registrar did not accept the renewal.');
return;
}
$this->markRenewalComplete($order, $customerId, $rcOrderId);
}
private function markRenewalComplete(RcServiceOrder $order, string $customerId, string $rcOrderId): void
{
$details = $this->products->getOrderDetails($order->category === 'domain-renewal' ? 'domain-registration' : $order->category, $rcOrderId);
if ($details['success'] ?? false) {
$synced = $this->products->syncOrderToLocal(
$order->category === 'domain-renewal' ? 'domain-registration' : $order->category,
(array) ($details['order'] ?? []),
$order->user_id,
$customerId,
$order
);
$synced->forceFill([
'status' => $synced->status === RcServiceOrder::STATUS_ACTIVE
? RcServiceOrder::STATUS_ACTIVE
: RcServiceOrder::STATUS_PROCESSING,
'payment_status' => RcServiceOrder::PAYMENT_STATUS_PAID,
'fulfillment_status' => RcServiceOrder::FULFILLMENT_FULFILLED,
'rc_order_id' => $rcOrderId,
'submitted_at' => $synced->submitted_at ?: now(),
'last_synced_at' => now(),
])->save();
return;
}
$order->forceFill([
'rc_customer_id' => $customerId,
'rc_order_id' => $rcOrderId,
'status' => RcServiceOrder::STATUS_ACTIVE,
'fulfillment_status' => RcServiceOrder::FULFILLMENT_FULFILLED,
'submitted_at' => $order->submitted_at ?: now(),
'last_synced_at' => now(),
])->save();
}
private function submitServiceOrder(RcServiceOrder $order, string $customerId): void
{
$input = (array) Arr::get($order->meta ?? [], 'order_input', []);
$input['domain_name'] = $input['domain_name'] ?? $order->domain_name;
$input['plan_id'] = $input['plan_id'] ?? $order->plan_id;
$input['months'] = $input['months'] ?? $order->term_months ?? 1;
$result = $this->products->order($order->category, $customerId, $input);
if (! ($result['success'] ?? false)) {
$this->markManualReview($order, $result['message'] ?? 'The provisioning request could not be submitted.');
return;
}
$orderId = (string) ($result['order_id'] ?? '');
if ($orderId === '') {
$this->markManualReview($order, 'The provisioning request did not return an upstream order id.');
return;
}
$details = $this->products->getOrderDetails($order->category, $orderId);
if ($details['success'] ?? false) {
$synced = $this->products->syncOrderToLocal(
$order->category,
(array) ($details['order'] ?? []),
$order->user_id,
$customerId,
$order
);
$synced->forceFill([
'status' => $synced->status === RcServiceOrder::STATUS_ACTIVE
? RcServiceOrder::STATUS_ACTIVE
: RcServiceOrder::STATUS_PROCESSING,
'payment_status' => RcServiceOrder::PAYMENT_STATUS_PAID,
'fulfillment_status' => $synced->status === RcServiceOrder::STATUS_ACTIVE
? RcServiceOrder::FULFILLMENT_FULFILLED
: RcServiceOrder::FULFILLMENT_AWAITING_VENDOR,
'submitted_at' => $synced->submitted_at ?: now(),
'last_synced_at' => now(),
])->save();
return;
}
$this->markAwaitingVendor($order, $customerId, $orderId, $details['message'] ?? null);
}
private function markAwaitingVendor(RcServiceOrder $order, string $customerId, string $orderId, ?string $message = null): void
{
$meta = (array) ($order->meta ?? []);
if ($message !== null && $message !== '') {
$meta['last_message'] = $message;
}
$order->forceFill([
'rc_customer_id' => $customerId,
'rc_order_id' => $orderId !== '' ? $orderId : $order->rc_order_id,
'status' => RcServiceOrder::STATUS_PROCESSING,
'fulfillment_status' => RcServiceOrder::FULFILLMENT_AWAITING_VENDOR,
'submitted_at' => $order->submitted_at ?: now(),
'last_synced_at' => now(),
'meta' => $meta,
])->save();
}
private function markManualReview(RcServiceOrder $order, string $message): void
{
$meta = (array) ($order->meta ?? []);
$meta['last_message'] = $message;
$order->forceFill([
'status' => RcServiceOrder::STATUS_PROCESSING,
'fulfillment_status' => RcServiceOrder::FULFILLMENT_MANUAL_REVIEW,
'meta' => $meta,
])->save();
}
}