Skip to content

Commit

Permalink
Merge pull request #1354 from bakaphp/hotfix-shopify-sync-price-stock
Browse files Browse the repository at this point in the history
fix: shopify sync
  • Loading branch information
kaioken authored May 20, 2024
2 parents f1812bb + 037c4c3 commit ec6d2c7
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace App\Console\Commands\Shopify;
namespace App\Console\Commands\Connectors\Shopify;

use Illuminate\Console\Command;
use Kanvas\Apps\Models\Apps;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

declare(strict_types=1);

namespace App\Console\Commands\Shopify;
namespace App\Console\Commands\Connectors\Shopify;

use Illuminate\Console\Command;
use Kanvas\Apps\Models\Apps;
use Kanvas\Companies\Models\Companies;
use Kanvas\Connectors\Shopify\Enums\StatusEnum;
use Kanvas\Connectors\Shopify\Services\ShopifyInventoryService;
use Kanvas\Inventory\Channels\Models\Channels;
use Kanvas\Inventory\Products\Models\Products;
use Kanvas\Inventory\Warehouses\Models\Warehouses;
use Kanvas\Users\Models\UserCompanyApps;

class ShopifyInventorySyncCommand extends Command
Expand All @@ -19,7 +21,7 @@ class ShopifyInventorySyncCommand extends Command
*
* @var string
*/
protected $signature = 'kanvas:inventory-shopify-sync {app_id} {company_id}';
protected $signature = 'kanvas:inventory-shopify-sync {app_id} {company_id} {warehouse_id} {channel_id}';

/**
* The console command description.
Expand All @@ -37,26 +39,24 @@ public function handle()
{
$app = Apps::getById((int) $this->argument('app_id'));
$company = Companies::getById((int) $this->argument('company_id'));
$channel = Channels::getByIdFromCompany((int) $this->argument('channel_id'), $company);
$warehouses = Warehouses::getByIdFromCompany((int) $this->argument('warehouse_id'), $company);

$associatedApps = UserCompanyApps::where('apps_id', $app->getId())
->where('companies_id', $company->getId())->first();
->where('companies_id', $company->getId())->first();

$companyData = $associatedApps->company;
$this->info("Checking company {$companyData->getId()} \n");

$products = Products::where('companies_id', $companyData->getId())
->where('apps_id', $app->getId())
->get();
->where('apps_id', $app->getId())
->get();

foreach ($products as $product) {
$this->info("Checking product {$product->getId()} {$product->name} \n");

foreach ($product->variants as $variant) {
$variant->warehouses->map(function ($warehouses) use ($variant) {
$shopifyService = new ShopifyInventoryService($variant->app, $variant->company, $warehouses);
$shopifyService->saveProduct($variant->product, StatusEnum::ACTIVE);
});
}
$shopifyService = new ShopifyInventoryService($product->app, $product->company, $warehouses);
$shopifyService->saveProduct($product, StatusEnum::ACTIVE, $channel);
}
return;
}
Expand Down
107 changes: 107 additions & 0 deletions src/Domains/Connectors/Shopify/Services/ShopifyImageService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?php

declare(strict_types=1);

namespace Kanvas\Connectors\Shopify\Services;

use Baka\Contracts\AppInterface;
use Baka\Contracts\CompanyInterface;
use Exception;
use Kanvas\Connectors\Shopify\Client;
use Kanvas\Inventory\Products\Models\Products;
use Kanvas\Inventory\Regions\Models\Regions;
use Kanvas\Inventory\Variants\Models\Variants;
use PHPShopify\ShopifySDK;

class ShopifyImageService
{
protected ShopifySDK $shopifySdk;

public function __construct(
protected AppInterface $app,
protected CompanyInterface $company,
protected Regions $region,
) {
$this->shopifySdk = Client::getInstance($app, $company, $region);
}

public function processEntityImage(Products|Variants $entity): int
{
$totalUploaded = 0;
if (! $entity->files->count()) {
return $totalUploaded;
}

foreach ($entity->files as $file) {
if ($entity instanceof Products) {
if ($this->addImage($entity, $file->url)) {
$totalUploaded++;
}
} else {
if ($this->addVariantImage($entity, $file->url)) {
$totalUploaded++;
}
}
}

return $totalUploaded;
}

public function addImage(Products $product, string $imageUrl): ?array
{
try {
$shopifyProduct = $this->shopifySdk->Product($product->getShopifyId($this->region));

$fileName = pathinfo($imageUrl, PATHINFO_BASENAME);
// Check if the image already exists
$existingImages = $shopifyProduct->Image->get();
foreach ($existingImages as $image) {
if ($image['alt'] === $fileName) {
return null; // Image already exists, no need to upload
}
}

// Add the image if it does not exist
$response = $shopifyProduct->Image->post(['src' => $imageUrl, 'alt' => $fileName]);
return $response;
} catch (Exception $e) {
throw new Exception('Failed to add image to Shopify product: ' . $e->getMessage());
}
}

public function addVariantImage(Variants $variant, string $imageUrl): bool
{
try {
$shopifyProduct = $this->shopifySdk->Product($variant->product->getShopifyId($this->region));
$shopifyVariant = $shopifyProduct->Variant($variant->getShopifyId($this->region));

// Check if the image already exists
$existingImages = $shopifyProduct->Image->get();
$fileName = pathinfo($imageUrl, PATHINFO_BASENAME);

foreach ($existingImages as $image) {
if ($image['alt'] === $fileName) {
return false; // Image already exists, no need to upload
}
}

// Add the image if it does not exist
$image = $this->addImage($variant->product, $imageUrl);

if ($image) {
$shopifyVariantData = $shopifyVariant->get();
$shopifyVariant->put(['image_id' => $image['id']]);

if ($shopifyVariantData['image_id'] !== null) {
$shopifyProduct->Image($shopifyVariantData['image_id'])->delete();
}

return true;
}

return false;
} catch (Exception $e) {
throw new Exception('Failed to add image to Shopify variant: ' . $e->getMessage());
}
}
}
50 changes: 23 additions & 27 deletions src/Domains/Connectors/Shopify/Services/ShopifyInventoryService.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,29 @@
use Kanvas\Connectors\Shopify\Enums\StatusEnum;
use Kanvas\Inventory\Channels\Models\Channels;
use Kanvas\Inventory\Products\Models\Products;
use Kanvas\Inventory\Regions\Models\Regions;
use Kanvas\Inventory\Variants\Models\Variants;
use Kanvas\Inventory\Warehouses\Models\Warehouses;
use Kanvas\Social\Channels\Models\Channel;
use PHPShopify\ShopifySDK;
use Throwable;

class ShopifyInventoryService
{
protected ShopifySDK $shopifySdk;
protected ShopifyImageService $shopifyImageService;

public function __construct(
protected AppInterface $app,
protected CompanyInterface $company,
protected Warehouses $warehouses,
) {
$this->shopifySdk = Client::getInstance($app, $company, $warehouses->regions);
$this->shopifyImageService = new ShopifyImageService($app, $company, $warehouses->regions);
}

/**
* Map and create an product on shopify sdk.
*/
public function saveProduct(Products $product, StatusEnum $status): array
public function saveProduct(Products $product, StatusEnum $status, ?Channels $channel = null): array
{
$shopifyProductId = $product->getShopifyId($this->warehouses->regions);

Expand All @@ -54,15 +54,19 @@ public function saveProduct(Products $product, StatusEnum $status): array
$response = $this->shopifySdk->Product->post($productInfo);
$shopifyProductId = $response['id'];
$product->setShopifyId($this->warehouses->regions, $shopifyProductId);

foreach ($response['variants'] as $shopifyVariant) {
$variant = $product->variants('sku', $shopifyVariant['sku'])->first();
if ($variant->getShopifyId($this->warehouses->regions) === null) {
$variant->setShopifyId($this->warehouses->regions, $shopifyVariant['id']);
}
}
} else {
$shopifyProduct = $this->shopifySdk->Product($shopifyProductId);
$response = $shopifyProduct->put($productInfo);
}

foreach ($response['variants'] as $shopifyVariant) {
$variant = $product->variants('sku', $shopifyVariant['sku'])->first();
if ($variant->getShopifyId($this->warehouses->regions) === null) {
$variant->setShopifyId($this->warehouses->regions, $shopifyVariant['id']);
foreach ($product->variants as $variant) {
$this->saveVariant($variant, $channel);
}
}

Expand All @@ -76,13 +80,15 @@ public function saveProduct(Products $product, StatusEnum $status): array
//do nothing
}

$this->shopifyImageService->processEntityImage($product);

return $response;
}

/**
* Map the data from the variant into the array
*/
public function mapVariant(Variants $variant, ?Channel $channel = null): array
public function mapVariant(Variants $variant, ?Channels $channel = null): array
{
$warehouseInfo = $variant->variantWarehouses()->where('warehouses_id', $this->warehouses->getId());

Expand All @@ -99,16 +105,21 @@ public function mapVariant(Variants $variant, ?Channel $channel = null): array
$price = $warehouseInfo?->price ?? 0;
}

$quantity = $warehouseInfo?->quantity ?? 0;
$shopifyVariantInfo = [
'option1' => $variant->sku ?? $variant->name,
'sku' => $variant->sku,
'barcode' => $variant->barcode,
'price' => $price,
'quantity' => $warehouseInfo?->quantity ?? 0,
'quantity' => $quantity,
'compare_at_price' => $discountedPrice ?? 0,
'inventory_policy' => 'deny',
];

if ($quantity > 0) {
$this->setStock($variant, $channel);
}

if ($variant->product->getShopifyId($this->warehouses->regions)) {
$shopifyVariantInfo['product_id'] = $variant->product->getShopifyId($this->warehouses->regions);
}
Expand Down Expand Up @@ -139,6 +150,8 @@ public function saveVariant(Variants $variant, Channels $channel = null): array
}
}

$this->shopifyImageService->processEntityImage($variant);

return $response;
}

Expand Down Expand Up @@ -196,21 +209,4 @@ public function publishProduct(Products $product): array
{
return $this->changeProductStatus($product, StatusEnum::ACTIVE);
}

public function addImages(Variants $variant, string $imageUrl): void
{
$shopifyProduct = $this->shopifySdk->Product($variant->product->getShopifyId($this->warehouses->regions));
$shopifyVariant = $shopifyProduct->Variant($variant->getShopifyId($this->warehouses->regions));

$shopifyVariantData = $shopifyVariant->get();

//product will have all the images of its variants
$image = $shopifyProduct->Image->post(['src' => $imageUrl]);

$shopifyVariant->put(['image_id' => $image['id']]);

if ($shopifyVariantData['image_id'] !== null) {
$shopifyProduct->Image($shopifyVariantData['image_id'])->delete();
}
}
}
5 changes: 4 additions & 1 deletion src/Kanvas/Filesystem/Traits/HasFilesystemTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ public function getFileByName(string $name): ?FilesystemEntities
*/
public function files(): HasManyThrough
{
$app = $this->app ?? app(Apps::class);
$systemModule = SystemModulesRepository::getByModelName(get_class($this), $app);

return $this->hasManyThrough(
Filesystem::class,
FilesystemEntities::class,
Expand All @@ -134,7 +137,7 @@ public function files(): HasManyThrough
'filesystem_id'
)->where(
'filesystem_entities.system_modules_id',
SystemModulesRepository::getByModelName(get_class($this))->getId()
$systemModule->getId()
)
->where(
'filesystem_entities.is_deleted',
Expand Down
20 changes: 9 additions & 11 deletions tests/Connectors/Integration/Shopify/VariantTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@

namespace Tests\Connectors\Integration\Shopify;

use Kanvas\Connectors\Shopify\DataTransferObject\Shopify;
use Kanvas\Connectors\Shopify\Enums\StatusEnum;
use Kanvas\Connectors\Shopify\Services\ShopifyConfigurationService;
use Kanvas\Connectors\Shopify\Services\ShopifyImageService;
use Kanvas\Connectors\Shopify\Services\ShopifyInventoryService;
use Tests\Connectors\Traits\HasShopifyConfiguration;
use Kanvas\Inventory\Channels\Models\Channels;
use Kanvas\Inventory\Products\Models\Products;
use Kanvas\Inventory\Regions\Models\Regions;
use Tests\Connectors\Traits\HasShopifyConfiguration;
use Tests\TestCase;

final class VariantTest extends TestCase
Expand Down Expand Up @@ -96,18 +94,18 @@ public function testSetImage()
$warehouse
);

$shopifyImageService = new ShopifyImageService(
$product->app,
$product->company,
$warehouse->region
);

$shopifyProduct = $shopify->saveProduct($product, StatusEnum::ACTIVE);
$url = 'https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png';

foreach ($product->variants as $variant) {
$shopify->saveVariant($variant);
$shopifyVariantResponse = $shopify->addImages($variant, $url);

$this->assertEquals(
$variant->image,
$shopifyVariantResponse
);
$this->assertTrue($shopifyImageService->addVariantImage($variant, $url));
//$shopifyVariantResponse = $shopify->addImages($variant, $url);
}
}
}

0 comments on commit ec6d2c7

Please sign in to comment.