从OC导入产品数据脚本
This commit is contained in:
parent
1f15bbda6f
commit
9f3946253a
|
|
@ -24,6 +24,7 @@ use Beike\Admin\View\Components\NoData;
|
|||
use Beike\Admin\View\Components\Sidebar;
|
||||
use Beike\Console\Commands\GenerateDatabaseDict;
|
||||
use Beike\Console\Commands\MakeRootAdminUser;
|
||||
use Beike\Console\Commands\MigrateFromOpenCart;
|
||||
use Beike\Console\Commands\Sitemap;
|
||||
use Beike\Models\AdminUser;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
|
@ -83,8 +84,9 @@ class AdminServiceProvider extends ServiceProvider
|
|||
if ($this->app->runningInConsole()) {
|
||||
$this->commands([
|
||||
MakeRootAdminUser::class,
|
||||
Sitemap::class,
|
||||
MigrateFromOpenCart::class,
|
||||
GenerateDatabaseDict::class,
|
||||
Sitemap::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,390 @@
|
|||
<?php
|
||||
/**
|
||||
* MigrateFromOpenCart.php
|
||||
*
|
||||
* @copyright 2023 beikeshop.com - All Rights Reserved
|
||||
* @link https://beikeshop.com
|
||||
* @author Edward Yang <yangjin@guangda.work>
|
||||
* @created 2023-01-03 18:57:53
|
||||
* @modified 2023-01-03 18:57:53
|
||||
*/
|
||||
|
||||
namespace Beike\Console\Commands;
|
||||
|
||||
use Beike\Admin\Services\ProductService;
|
||||
use Beike\Models\Brand;
|
||||
use Beike\Models\Product;
|
||||
use Beike\Models\ProductDescription;
|
||||
use Beike\Models\ProductSku;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class MigrateFromOpenCart extends Command
|
||||
{
|
||||
public const PER_PAGE = 1000;
|
||||
|
||||
public const LANG_MAPPING = [
|
||||
'zh_cn' => 11,
|
||||
'es' => 6,
|
||||
];
|
||||
|
||||
protected $signature = 'migrate:oc';
|
||||
|
||||
protected $description = '从 OpenCart 迁移数据';
|
||||
|
||||
protected ConnectionInterface $ocdb;
|
||||
|
||||
private $ocProductVariants;
|
||||
|
||||
private $ocVariantDescriptions;
|
||||
|
||||
private $ocVariantValues;
|
||||
|
||||
private $ocVariantValueDescriptions;
|
||||
|
||||
private $ocProductImages;
|
||||
|
||||
private int $page = 1;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->ocdb = DB::connection('opencart');
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入OC产品数据
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// $this->importBrands();
|
||||
// $this->importProducts();
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入品牌数据
|
||||
*/
|
||||
private function importBrands()
|
||||
{
|
||||
Brand::query()->truncate();
|
||||
$this->ocdb->table('manufacturer')
|
||||
->orderBy('manufacturer_id')
|
||||
->chunk(self::PER_PAGE, function ($ocBrands) {
|
||||
$bkBrands = [];
|
||||
foreach ($ocBrands as $ocBrand) {
|
||||
$bkBrands[] = [
|
||||
'id' => $ocBrand->manufacturer_id,
|
||||
'name' => $ocBrand->name,
|
||||
'first' => mb_strtoupper(mb_substr($ocBrand->name, 0, 1)),
|
||||
'logo' => $ocBrand->image,
|
||||
'sort_order' => $ocBrand->sort_order,
|
||||
'status' => $ocBrand->status,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
];
|
||||
}
|
||||
Brand::query()->insert($bkBrands);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入产品
|
||||
*/
|
||||
private function importProducts()
|
||||
{
|
||||
$this->ocProductVariants = $this->ocdb->table('product_variant')->get()->groupBy('product_id');
|
||||
$this->ocVariantDescriptions = $this->ocdb->table('variant_description')->get()->groupBy('variant_id');
|
||||
$this->ocVariantValues = $this->ocdb->table('variant_value')->get()->keyBy('variant_value_id');
|
||||
$this->ocVariantValueDescriptions = $this->ocdb->table('variant_value_description')->get()->groupBy('variant_value_id');
|
||||
$this->ocProductImages = $this->ocdb->table('product_image')->get()->groupBy('product_id');
|
||||
|
||||
$this->clearData();
|
||||
$this->ocdb->table('product')
|
||||
->where('parent_id', 0)
|
||||
// ->where('product_id', 1894)
|
||||
// ->where('sku', '10012378')
|
||||
->orderBy('product_id')
|
||||
->chunk(self::PER_PAGE, function ($ocProducts) {
|
||||
$this->importProduct($ocProducts);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入单个产品
|
||||
* @param Collection $ocProducts
|
||||
*/
|
||||
private function importProduct(Collection $ocProducts)
|
||||
{
|
||||
$total = $ocProducts->count();
|
||||
$ocProductIds = $ocProducts->pluck('product_id');
|
||||
$childProducts = $this->ocdb->table('product')->whereIn('parent_id', $ocProductIds)->get()->groupBy('parent_id');
|
||||
foreach ($ocProducts as $index => $ocProduct) {
|
||||
dump("Start handle Page: $this->page - {$index}/{$total}");
|
||||
$ocProductId = $ocProduct->product_id;
|
||||
$productVariants = $this->ocProductVariants[$ocProductId] ?? [];
|
||||
$childProducts = $childProducts[$ocProductId] ?? [];
|
||||
$bkProduct = $this->generateBeikeProduct($ocProduct, $productVariants, $childProducts);
|
||||
(new ProductService)->create($bkProduct);
|
||||
}
|
||||
$this->page++;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造 beike 产品
|
||||
*/
|
||||
private function generateBeikeProduct($ocProduct, $productVariants, $childProducts)
|
||||
{
|
||||
$variables = $this->generateVariables($ocProduct, $childProducts);
|
||||
$bkProduct = [
|
||||
'active' => $ocProduct->status,
|
||||
'brand_id' => $ocProduct->manufacturer_id,
|
||||
'position' => $ocProduct->sort_order,
|
||||
'tax_class_id' => $ocProduct->tax_class_id,
|
||||
'variables' => json_encode($variables),
|
||||
];
|
||||
$bkProduct['descriptions'] = $this->generateDescriptions($ocProduct);
|
||||
$bkProduct['images'] = [$ocProduct->image];
|
||||
$bkProduct['skus'] = $this->generateSkus($ocProduct, $productVariants, $childProducts, $variables);
|
||||
|
||||
return $bkProduct;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
*/
|
||||
private function generateVariables($ocProduct, $childProducts): array
|
||||
{
|
||||
$productIds = [$ocProduct->product_id];
|
||||
foreach ($childProducts as $childProduct) {
|
||||
$productIds[] = $childProduct->product_id;
|
||||
}
|
||||
|
||||
$locales = locales();
|
||||
$items = $values = [];
|
||||
foreach ($productIds as $productId) {
|
||||
$productVariants = $this->ocProductVariants[$productId] ?? [];
|
||||
foreach ($productVariants as $productVariant) {
|
||||
$productVariantId = $productVariant->variant_id;
|
||||
$productVariantValueId = $productVariant->variant_value_id;
|
||||
|
||||
$variants = $this->ocVariantDescriptions[$productVariantId];
|
||||
$variantValue = $this->ocVariantValues[$productVariantValueId];
|
||||
$variantValueDescriptions = $this->ocVariantValueDescriptions[$productVariantValueId];
|
||||
|
||||
$variants = $variants->keyBy('language_id');
|
||||
$names = [];
|
||||
foreach ($locales as $locale) {
|
||||
$variant = $variants[self::LANG_MAPPING[$locale['code']]];
|
||||
$names[$locale['code']] = $variant->name;
|
||||
}
|
||||
|
||||
$valueNames = [];
|
||||
$variantValueDescriptions = $variantValueDescriptions->keyBy('language_id');
|
||||
foreach ($locales as $locale) {
|
||||
$variantValueDescription = $variantValueDescriptions[self::LANG_MAPPING[$locale['code']]];
|
||||
$valueNames[$locale['code']] = $variantValueDescription->name;
|
||||
}
|
||||
|
||||
$values[$productVariantValueId] = [
|
||||
'variant_value_id' => $productVariantValueId,
|
||||
'name' => $valueNames,
|
||||
'image' => $variantValue->image,
|
||||
];
|
||||
|
||||
$items[$productVariantId] = [
|
||||
'variant_id' => $productVariantId,
|
||||
'name' => $names,
|
||||
'values' => $values,
|
||||
'isImage' => (bool) $variantValue->image,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$items = array_values($items);
|
||||
foreach ($items as $index => $item) {
|
||||
$items[$index]['values'] = array_values($item['values']);
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 beike 产品描述
|
||||
* @param $ocProduct
|
||||
* @return array
|
||||
*/
|
||||
private function generateDescriptions($ocProduct): array
|
||||
{
|
||||
$descriptions = [];
|
||||
$locales = locales();
|
||||
$ocDescriptions = $this->ocdb->table('product_description')
|
||||
->where('product_id', $ocProduct->product_id)
|
||||
->get()
|
||||
->keyBy('language_id')
|
||||
->toArray();
|
||||
|
||||
foreach ($locales as $locale) {
|
||||
$ocDescription = $ocDescriptions[self::LANG_MAPPING[$locale['code']]];
|
||||
$descriptions[$locale['code']] = [
|
||||
'name' => $ocDescription->name,
|
||||
'content' => html_entity_decode($ocDescription->description),
|
||||
];
|
||||
}
|
||||
|
||||
return $descriptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 beike 产品 SKU
|
||||
*
|
||||
* @param $ocProduct
|
||||
* @param $productVariants
|
||||
* @param $childProducts
|
||||
* @param array $variables
|
||||
* @return array
|
||||
*/
|
||||
private function generateSkus($ocProduct, $productVariants, $childProducts, array $variables): array
|
||||
{
|
||||
// 简单商品
|
||||
if (count($productVariants) == 0) {
|
||||
return $this->generateSimpleSku($ocProduct);
|
||||
}
|
||||
|
||||
$masterSku = $childSkus = [];
|
||||
// 有主商品
|
||||
if (count($productVariants) > 0) {
|
||||
$masterSku = $this->generateMasterSku($ocProduct, $productVariants, $variables);
|
||||
}
|
||||
// 有子商品
|
||||
if (count($childProducts) > 0) {
|
||||
$childSkus = $this->generateChildSkus($childProducts, $variables);
|
||||
}
|
||||
if ($masterSku) {
|
||||
array_push($childSkus, $masterSku);
|
||||
}
|
||||
|
||||
return $childSkus;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取简单商品 SKU
|
||||
* @param $ocProduct
|
||||
* @return array[]
|
||||
*/
|
||||
private function generateSimpleSku($ocProduct): array
|
||||
{
|
||||
$images = $this->ocProductImages[$ocProduct->product_id] ?? [];
|
||||
|
||||
return [
|
||||
[
|
||||
'image' => $images,
|
||||
'model' => $ocProduct->model,
|
||||
'sku' => $ocProduct->sku,
|
||||
'price' => $ocProduct->price,
|
||||
'origin_price' => $ocProduct->price,
|
||||
'cost_price' => $ocProduct->cost_price,
|
||||
'quantity' => $ocProduct->quantity,
|
||||
'variants' => null,
|
||||
'position' => $ocProduct->sort_order,
|
||||
'is_default' => 1,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取主商品 SKU
|
||||
* @param $ocProduct
|
||||
* @param $productVariants
|
||||
* @param $variables
|
||||
* @return array
|
||||
*/
|
||||
private function generateMasterSku($ocProduct, $productVariants, $variables): array
|
||||
{
|
||||
$variants = $this->generateVariants($productVariants, $variables);
|
||||
$images = $this->ocProductImages[$ocProduct->product_id] ?? [];
|
||||
|
||||
return [
|
||||
'image' => $images,
|
||||
'model' => $ocProduct->model,
|
||||
'sku' => $ocProduct->sku,
|
||||
'price' => $ocProduct->price,
|
||||
'origin_price' => $ocProduct->price,
|
||||
'cost_price' => $ocProduct->cost_price,
|
||||
'quantity' => $ocProduct->quantity,
|
||||
'variants' => $variants,
|
||||
'position' => $ocProduct->sort_order,
|
||||
'is_default' => 1,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取子商品SKU
|
||||
* @param $childProducts
|
||||
* @param $variables
|
||||
* @return array
|
||||
*/
|
||||
private function generateChildSkus($childProducts, $variables): array
|
||||
{
|
||||
$items = [];
|
||||
foreach ($childProducts as $ocProduct) {
|
||||
$ocProductId = $ocProduct->product_id;
|
||||
$productVariants = $this->ocProductVariants[$ocProductId] ?? [];
|
||||
|
||||
$images = $this->ocProductImages[$ocProductId] ?? [];
|
||||
$variants = $this->generateVariants($productVariants, $variables);
|
||||
$items[] = [
|
||||
'image' => $images,
|
||||
'model' => $ocProduct->model,
|
||||
'sku' => $ocProduct->sku,
|
||||
'price' => $ocProduct->price,
|
||||
'origin_price' => $ocProduct->price,
|
||||
'cost_price' => $ocProduct->cost_price,
|
||||
'quantity' => $ocProduct->quantity,
|
||||
'variants' => $variants,
|
||||
'position' => $ocProduct->sort_order,
|
||||
'is_default' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成商品 SKU 多规格数据
|
||||
*
|
||||
* @param $productVariants
|
||||
* @param $variables
|
||||
* @return array
|
||||
*/
|
||||
private function generateVariants($productVariants, $variables): array
|
||||
{
|
||||
$items = [];
|
||||
foreach ($productVariants as $productVariant) {
|
||||
$variantId = $productVariant->variant_id;
|
||||
$variantValueId = $productVariant->variant_value_id;
|
||||
foreach ($variables as $index1 => $variable) {
|
||||
if ($variantId == $variable['variant_id']) {
|
||||
foreach ($variable['values'] as $index2 => $value) {
|
||||
if ($variantValueId == $value['variant_value_id']) {
|
||||
$items[$index1] = (string) $index2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空产品相关数据
|
||||
*/
|
||||
private function clearData()
|
||||
{
|
||||
Product::query()->truncate();
|
||||
ProductSku::query()->truncate();
|
||||
ProductDescription::query()->truncate();
|
||||
}
|
||||
}
|
||||
|
|
@ -63,6 +63,25 @@ return [
|
|||
]) : [],
|
||||
],
|
||||
|
||||
'opencart' => [
|
||||
'driver' => 'mysql',
|
||||
'host' => env('DB_HOST', '127.0.0.1'),
|
||||
'port' => env('DB_PORT', '3306'),
|
||||
'database' => env('OC_DATABASE', 'forge'),
|
||||
'username' => env('DB_USERNAME', 'forge'),
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
'unix_socket' => env('DB_SOCKET', ''),
|
||||
'charset' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'prefix' => env('OC_PREFIX', ''),
|
||||
'prefix_indexes' => true,
|
||||
'strict' => true,
|
||||
'engine' => 'InnoDB',
|
||||
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||
]) : [],
|
||||
],
|
||||
|
||||
'pgsql' => [
|
||||
'driver' => 'pgsql',
|
||||
'url' => env('DATABASE_URL'),
|
||||
|
|
|
|||
Loading…
Reference in New Issue