Deploy Ladill POS / deploy (push) Successful in 32s
Finish removing the upstream platform fork: drop the Hosting/SSL/Domain notification classes + their mail views, the email/mailbox/domains/hosting view trees, the Mini/Afia/search/paystack partials and unused components, and the now-orphan support helpers (DomainConfig, MailboxPricing, ResellerClubLegacy), SmsService, and fork configs (afia, hosting, domain, email, mailbox, qr, mail_brands, notifications, ...). Reparent the notifications page off the hosting layout onto the POS app layout (it had referenced undefined hosting./mini. routes). Computed the removable set from a reachability scan of the POS view graph; kept views reference no removed routes/services. Branding: favicon now uses the updated favicon.ico (favicon.svg removed); signed-out fallback logo points at the POS logo. CRM import: constrain the catalogue pull to type=product so CRM services are never imported as POS products (server-side filter + defensive client skip). Test suite green (8 passed, 29 assertions); all routes resolve and every remaining Blade compiles. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
65 lines
2.0 KiB
PHP
65 lines
2.0 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Import;
|
|
|
|
use App\Models\PosProduct;
|
|
use App\Services\Crm\CrmClient;
|
|
use RuntimeException;
|
|
|
|
class CrmProductImportService
|
|
{
|
|
/**
|
|
* @return array{imported: int, updated: int}
|
|
*/
|
|
public function import(string $ownerRef): array
|
|
{
|
|
// CRM catalogues both products and services; POS only stocks products.
|
|
$response = CrmClient::for($ownerRef)->products(['type' => 'product', 'active' => 1, 'per_page' => 500]);
|
|
$rows = (array) ($response['data'] ?? []);
|
|
|
|
if ($rows === []) {
|
|
throw new RuntimeException('No active products found in CRM.');
|
|
}
|
|
|
|
$imported = 0;
|
|
$updated = 0;
|
|
|
|
foreach ($rows as $row) {
|
|
// Defensive: skip services in case an older CRM API ignores the type filter.
|
|
if (($row['type'] ?? 'product') !== 'product') {
|
|
continue;
|
|
}
|
|
|
|
$name = trim((string) ($row['name'] ?? ''));
|
|
if ($name === '') {
|
|
continue;
|
|
}
|
|
|
|
$sku = isset($row['sku']) && $row['sku'] !== '' ? (string) $row['sku'] : null;
|
|
$matchQuery = PosProduct::owned($ownerRef)->where('name', $name);
|
|
if ($sku) {
|
|
$matchQuery = PosProduct::owned($ownerRef)->where(fn ($q) => $q->where('sku', $sku)->orWhere('name', $name));
|
|
}
|
|
$existing = $matchQuery->first();
|
|
|
|
$attrs = [
|
|
'name' => $name,
|
|
'sku' => $sku,
|
|
'price_minor' => max(0, (int) ($row['unit_price_minor'] ?? 0)),
|
|
'currency' => strtoupper((string) ($row['currency'] ?? config('pos.default_currency', 'GHS'))),
|
|
'is_active' => (bool) ($row['active'] ?? true),
|
|
];
|
|
|
|
if ($existing) {
|
|
$existing->update($attrs);
|
|
$updated++;
|
|
} else {
|
|
PosProduct::create([...$attrs, 'owner_ref' => $ownerRef]);
|
|
$imported++;
|
|
}
|
|
}
|
|
|
|
return compact('imported', 'updated');
|
|
}
|
|
}
|