1489 lines
60 KiB
PHP
1489 lines
60 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Classes\Settings;
|
|
use App\Helpers\ExtensionHelper;
|
|
use App\Models\ConfigOption;
|
|
use App\Models\Currency;
|
|
use App\Models\CustomProperty;
|
|
use App\Models\Gateway;
|
|
use App\Models\Price;
|
|
use App\Models\Server;
|
|
use App\Providers\SettingsProvider;
|
|
use Closure;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\Crypt;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Str;
|
|
use PDO;
|
|
use PDOException;
|
|
use PDOStatement;
|
|
use Throwable;
|
|
|
|
use function Laravel\Prompts\password;
|
|
use function Laravel\Prompts\text;
|
|
|
|
class MigrateOldData extends Command
|
|
{
|
|
/**
|
|
* The name and signature of the console command.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $signature = 'app:migrate-0.x {dbname} {username?} {host?} {port?}';
|
|
|
|
/**
|
|
* The console command description.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $description = 'Migrates all the data from paymenter version 0.x to 1.x';
|
|
|
|
/**
|
|
* The PDO connection to old database
|
|
*
|
|
* @var PDO
|
|
*/
|
|
protected $pdo;
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
protected $currency_code;
|
|
|
|
/**
|
|
* @var int
|
|
*/
|
|
protected $batchSize = 500;
|
|
|
|
public function handle()
|
|
{
|
|
$dbname = $this->argument('dbname');
|
|
$host = $this->askOrUseENV(argument: 'host', env: 'DB_HOST', question: 'Enter the host:', placeholder: 'localhost');
|
|
$port = $this->askOrUseENV(argument: 'port', env: 'DB_PORT', question: 'Enter the port:', placeholder: '3306');
|
|
$username = $this->askOrUseENV(argument: 'username', env: 'DB_USERNAME', question: 'Enter the username:', placeholder: 'paymenter');
|
|
$password = password("Enter the password for user '$username':", required: true);
|
|
|
|
try {
|
|
$this->pdo = new PDO("mysql:host=$host;port=$port;dbname=$dbname", $username, $password);
|
|
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
$this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
|
$this->info('Connected to old database, Starting migration...');
|
|
|
|
DB::statement('SET foreign_key_checks=0');
|
|
|
|
$this->defaultCurrency();
|
|
$this->migrateSettings();
|
|
$this->migrateConfigOptions();
|
|
$this->migrateCoupons();
|
|
$this->migrateCategories();
|
|
$this->migrateUsers();
|
|
$this->migrateTickets();
|
|
$this->migrateTicketMessages();
|
|
$this->migrateTaxRates();
|
|
$this->migrateExtensions();
|
|
$this->migrateProducts();
|
|
$this->migrateProductUpgrades();
|
|
$this->migrateConfigOptionProducts();
|
|
$this->migratePlans();
|
|
$this->migrateOrdersAndServices();
|
|
$this->migrateServiceConfigs();
|
|
$this->migrateServiceCancellations();
|
|
$this->migrateInvoices();
|
|
|
|
DB::statement('SET foreign_key_checks=1');
|
|
|
|
SettingsProvider::flushCache();
|
|
} catch (PDOException $e) {
|
|
$this->fail('Connection failed: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
protected function askOrUseENV(string $argument, string $env, string $question, string $placeholder): string
|
|
{
|
|
$arg_value = $this->argument($argument);
|
|
if ($arg_value) {
|
|
return $arg_value;
|
|
}
|
|
|
|
$env_value = env($env);
|
|
if (!is_null($env_value) && $env_value !== '') {
|
|
return $env_value;
|
|
}
|
|
|
|
return text($question, required: true, placeholder: $placeholder);
|
|
}
|
|
|
|
protected function migrateInBatch(string $table, string $query, Closure $processor)
|
|
{
|
|
/**
|
|
* @var PDOStatement $stmt
|
|
*/
|
|
$stmt = $this->pdo->prepare($query);
|
|
|
|
$offset = 0;
|
|
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
|
|
$stmt->bindValue(':limit', $this->batchSize, PDO::PARAM_INT);
|
|
$stmt->execute();
|
|
|
|
$nRows = $this->pdo->query('SELECT COUNT(*) FROM ' . $table)->fetchColumn();
|
|
|
|
if ($nRows <= $this->batchSize) {
|
|
$records = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
try {
|
|
$processor($records);
|
|
} catch (Throwable $th) {
|
|
Log::error($th);
|
|
$this->fail($th->getMessage());
|
|
}
|
|
} else {
|
|
$bar = $this->output->createProgressBar(round($nRows / $this->batchSize));
|
|
$bar->setFormat("Batch: %current%/%max% [%bar%] %percent:3s%%\n");
|
|
$bar->start();
|
|
while ($records = $stmt->fetchAll(PDO::FETCH_ASSOC)) {
|
|
$offset += $this->batchSize;
|
|
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
|
|
$stmt->execute();
|
|
|
|
try {
|
|
$processor($records);
|
|
} catch (Throwable $th) {
|
|
Log::error($th);
|
|
$this->fail($th->getMessage());
|
|
}
|
|
|
|
$bar->advance();
|
|
}
|
|
|
|
$bar->finish();
|
|
}
|
|
|
|
$this->info('Done.');
|
|
}
|
|
|
|
protected function defaultCurrency()
|
|
{
|
|
// Get default currency
|
|
$currency_settings = $this->pdo->query("SELECT * FROM `settings` WHERE `key` = 'currency' or `key` = 'currency_sign' or `key` = 'currency_position'")->fetchAll();
|
|
$currency_settings = array_combine(array_column($currency_settings, 'key'), $currency_settings);
|
|
$this->currency_code = $currency_settings['currency']['value'];
|
|
|
|
// Remove all the pre-existing currencies, in case the user still want's to use single currency
|
|
Currency::truncate();
|
|
Currency::create([
|
|
'name' => $this->currency_code,
|
|
'code' => $this->currency_code,
|
|
'prefix' => $currency_settings['currency_position']['value'] === 'left' ? $currency_settings['currency_sign']['value'] : null,
|
|
'suffix' => $currency_settings['currency_position']['value'] === 'right' ? $currency_settings['currency_sign']['value'] : null,
|
|
'format' => '1,000.00',
|
|
]);
|
|
}
|
|
|
|
protected function migrateSettings()
|
|
{
|
|
$stmt = $this->pdo->query('SELECT * FROM settings');
|
|
$records = $stmt->fetchAll();
|
|
|
|
// Map of settings which are just renamed
|
|
$old_to_new_map = [
|
|
// General
|
|
'timezone' => 'timezone',
|
|
'language' => 'app_language',
|
|
'app_logo' => 'logo',
|
|
'home_page_text' => 'theme_default_home_page_text',
|
|
|
|
// Security
|
|
'recaptcha_site_key' => 'captcha_site_key',
|
|
'recaptcha_secret_key' => 'captcha_secret',
|
|
|
|
// Social Login
|
|
'google_enabled' => 'oauth_google',
|
|
'google_client_id' => 'oauth_google_client_id',
|
|
'google_client_secret' => 'oauth_google_client_secret',
|
|
'github_enabled' => 'oauth_github',
|
|
'github_client_id' => 'oauth_github_client_id',
|
|
'github_client_secret' => 'oauth_github_client_secret',
|
|
'discord_enabled' => 'oauth_discord',
|
|
'discord_client_id' => 'oauth_discord_client_id',
|
|
'discord_client_secret' => 'oauth_discord_client_secret',
|
|
|
|
// Company Details
|
|
'company_name' => 'company_name',
|
|
'company_email' => 'company_email',
|
|
'company_phone' => 'company_phone',
|
|
'company_address' => 'company_address',
|
|
'company_city' => 'company_city',
|
|
'company_zip' => 'company_zip',
|
|
|
|
// Tax
|
|
'tax_enabled' => 'tax_enabled',
|
|
'tax_type' => 'tax_type',
|
|
|
|
// Mail
|
|
'mail_disabled' => 'mail_disable',
|
|
'must_verify_email' => 'mail_must_verify',
|
|
'mail_host' => 'mail_host',
|
|
'mail_port' => 'mail_port',
|
|
'mail_username' => 'mail_username',
|
|
'mail_password' => 'mail_password',
|
|
'mail_encryption' => 'mail_encryption',
|
|
'mail_from_address' => 'mail_from_address',
|
|
'mail_from_name' => 'mail_from_name',
|
|
|
|
// Other
|
|
'currency' => 'default_currency',
|
|
];
|
|
|
|
$settings = [];
|
|
foreach ($records as $old_setting) {
|
|
$key = $old_to_new_map[$old_setting['key']] ?? $old_setting['key'];
|
|
$value = $old_setting['value'];
|
|
|
|
// Migrate old settings directly if it is only renamed
|
|
if (array_key_exists($old_setting['key'], $old_to_new_map)) {
|
|
$avSetting = Settings::getSetting($key);
|
|
|
|
$settings[] = [
|
|
'key' => $key,
|
|
'value' => $value,
|
|
'type' => $avSetting->database_type ?? 'string',
|
|
'settingable_type' => null,
|
|
'settingable_id' => null,
|
|
'encrypted' => $avSetting->encrypted ?? false,
|
|
'created_at' => $old_setting['created_at'],
|
|
'updated_at' => $old_setting['updated_at'],
|
|
];
|
|
} else {
|
|
// Manually migrate completely or partially changed settings
|
|
if ($key === 'recaptcha_type') {
|
|
$setting_id = array_search('recaptcha', array_column($records, 'key'));
|
|
$captcha_disabled = $records[$setting_id]['value'] === '0';
|
|
|
|
$settings[] = [
|
|
'key' => 'captcha',
|
|
'value' => $captcha_disabled ? 'disabled' : match ($value) {
|
|
'v2' => 'recaptcha-v2',
|
|
'v3' => 'recaptcha-v3',
|
|
default => $value
|
|
},
|
|
'type' => 'string',
|
|
'settingable_type' => null,
|
|
'settingable_id' => null,
|
|
'encrypted' => false,
|
|
'created_at' => $old_setting['created_at'],
|
|
'updated_at' => $old_setting['updated_at'],
|
|
];
|
|
} elseif ($key === 'company_country') {
|
|
$settings[] = [
|
|
'key' => $key,
|
|
'value' => array_flip((array) config('app.countries'))[$value],
|
|
'type' => 'string',
|
|
'settingable_type' => null,
|
|
'settingable_id' => null,
|
|
'encrypted' => false,
|
|
'created_at' => $old_setting['created_at'],
|
|
'updated_at' => $old_setting['updated_at'],
|
|
];
|
|
} elseif (in_array($key, [
|
|
'requiredClientDetails_address',
|
|
'requiredClientDetails_city',
|
|
'requiredClientDetails_zip',
|
|
'requiredClientDetails_country',
|
|
'requiredClientDetails_phone',
|
|
])) {
|
|
$key = str_replace('requiredClientDetails_', '', $key);
|
|
$property = CustomProperty::where('name', $key)->first();
|
|
if ($property) {
|
|
$property->update(['required' => $value === '1']);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($settings as $value) {
|
|
DB::table('settings')->updateOrInsert(['key' => $value['key']], $value);
|
|
}
|
|
$this->info('Migrated settings!');
|
|
}
|
|
|
|
protected function migrateConfigOptions()
|
|
{
|
|
$this->info('Migrating Config Options...');
|
|
$this->migrateInBatch('configurable_options', 'SELECT c.id, c.name, c.type, c.order, c.hidden, c.group_id, g.name AS group_name, g.description AS group_description, g.products, c.created_at, c.updated_at FROM configurable_options as c JOIN configurable_option_groups as g ON c.group_id = g.id LIMIT :limit OFFSET :offset', function ($records) {
|
|
$records = array_map(function ($record) {
|
|
$option = explode('|', $record['name'], 2);
|
|
$env_variable = $option[0];
|
|
$name = $option[1] ?? $env_variable;
|
|
|
|
return [
|
|
'id' => $record['id'],
|
|
'name' => trim($name),
|
|
'env_variable' => $env_variable ? trim($env_variable) : trim($name),
|
|
'type' => match ($record['type']) {
|
|
'quantity' => 'number',
|
|
'slider' => 'select',
|
|
default => $record['type']
|
|
},
|
|
// TODO: migrate sort, or not
|
|
'sort' => null,
|
|
'hidden' => $record['hidden'],
|
|
'parent_id' => null,
|
|
|
|
'created_at' => $record['created_at'],
|
|
'updated_at' => $record['updated_at'],
|
|
];
|
|
}, $records);
|
|
|
|
DB::table('config_options')->insert($records);
|
|
});
|
|
|
|
$this->migrateInBatch('configurable_option_inputs', 'SELECT * FROM configurable_option_inputs LIMIT :limit OFFSET :offset', function ($option_inputs) {
|
|
$option_inputs = array_map(function ($record) {
|
|
$option = explode('|', $record['name'], 2);
|
|
$env_variable = $option[0];
|
|
$name = $option[1] ?? $env_variable;
|
|
|
|
return [
|
|
'id' => $record['id'],
|
|
'name' => trim($name),
|
|
'env_variable' => $env_variable ? trim($env_variable) : trim($name),
|
|
'type' => null,
|
|
// TODO: migrate sort, or not
|
|
'sort' => null,
|
|
'hidden' => $record['hidden'],
|
|
|
|
'parent_id' => $record['option_id'],
|
|
'created_at' => $record['created_at'],
|
|
'updated_at' => $record['updated_at'],
|
|
];
|
|
}, $option_inputs);
|
|
|
|
foreach ($option_inputs as $input) {
|
|
|
|
$input_id = $input['id'];
|
|
$inputs_stmt = $this->pdo->query("SELECT * FROM configurable_option_input_pricing WHERE `input_id` = $input_id");
|
|
$record = $inputs_stmt->fetchAll()[0];
|
|
|
|
if (
|
|
is_null($record['monthly']) &&
|
|
is_null($record['quarterly']) &&
|
|
is_null($record['semi_annually']) &&
|
|
is_null($record['annually']) &&
|
|
is_null($record['biennially']) &&
|
|
is_null($record['triennially'])
|
|
) {
|
|
unset($input['id']);
|
|
$new_id = DB::table('config_options')->insertGetId($input);
|
|
|
|
// Option is free
|
|
$input_plan = [
|
|
'name' => 'Free',
|
|
'type' => 'free',
|
|
'priceable_id' => $new_id,
|
|
'priceable_type' => 'App\Models\ConfigOption',
|
|
];
|
|
|
|
$plan_id = DB::table('plans')->insertGetId($input_plan);
|
|
|
|
continue;
|
|
}
|
|
|
|
if (
|
|
$record['monthly'] &&
|
|
is_null($record['quarterly']) &&
|
|
is_null($record['semi_annually']) &&
|
|
is_null($record['annually']) &&
|
|
is_null($record['biennially']) &&
|
|
is_null($record['triennially'])
|
|
) {
|
|
unset($input['id']);
|
|
$new_id = DB::table('config_options')->insertGetId($input);
|
|
|
|
// Option is one-time
|
|
$input_plan = [
|
|
'name' => 'One Time',
|
|
'type' => 'one-time',
|
|
'priceable_id' => $new_id,
|
|
'priceable_type' => 'App\Models\ConfigOption',
|
|
];
|
|
|
|
$plan_id = DB::table('plans')->insertGetId($input_plan);
|
|
|
|
DB::table('prices')->insert([
|
|
'plan_id' => $plan_id,
|
|
'price' => $record['monthly'],
|
|
'setup_fee' => $record['monthly_setup'],
|
|
'currency_code' => $this->currency_code,
|
|
]);
|
|
|
|
continue;
|
|
}
|
|
|
|
if (
|
|
$record['monthly'] &&
|
|
is_null($record['quarterly']) &&
|
|
is_null($record['semi_annually']) &&
|
|
is_null($record['annually']) &&
|
|
is_null($record['biennially']) &&
|
|
is_null($record['triennially'])
|
|
) {
|
|
unset($input['id']);
|
|
$new_id = DB::table('config_options')->insertGetId($input);
|
|
|
|
// Option is one-time
|
|
$input_plan = [
|
|
'name' => 'One Time',
|
|
'type' => 'one-time',
|
|
'priceable_id' => $new_id,
|
|
'priceable_type' => 'App\Models\ConfigOption',
|
|
];
|
|
|
|
$plan_id = DB::table('plans')->insertGetId($input_plan);
|
|
|
|
DB::table('prices')->insert([
|
|
'plan_id' => $plan_id,
|
|
'price' => $record['monthly'],
|
|
'setup_fee' => $record['monthly_setup'],
|
|
'currency_code' => $this->currency_code,
|
|
]);
|
|
|
|
continue;
|
|
}
|
|
|
|
if (
|
|
$record['monthly'] &&
|
|
($record['quarterly'] ||
|
|
$record['semi_annually'] ||
|
|
$record['annually'] ||
|
|
$record['biennially'] ||
|
|
$record['triennially']
|
|
)
|
|
) {
|
|
unset($input['id']);
|
|
$new_id = DB::table('config_options')->insertGetId($input);
|
|
|
|
$common_fields = [
|
|
'type' => 'recurring',
|
|
'priceable_id' => $new_id,
|
|
'priceable_type' => 'App\Models\ConfigOption',
|
|
];
|
|
|
|
$plans = [];
|
|
|
|
if ($record['monthly']) {
|
|
array_push($plans, array_merge([
|
|
'name' => 'Monthly',
|
|
'billing_period' => 1,
|
|
'billing_unit' => 'month',
|
|
'price' => [
|
|
'price' => $record['monthly'],
|
|
'setup_fee' => $record['monthly_setup'],
|
|
'currency_code' => $this->currency_code,
|
|
],
|
|
], $common_fields));
|
|
}
|
|
|
|
if ($record['quarterly']) {
|
|
array_push($plans, array_merge([
|
|
'name' => 'Quarterly',
|
|
'billing_period' => 3,
|
|
'billing_unit' => 'month',
|
|
'price' => [
|
|
'price' => $record['quarterly'],
|
|
'setup_fee' => $record['quarterly_setup'],
|
|
'currency_code' => $this->currency_code,
|
|
],
|
|
], $common_fields));
|
|
}
|
|
|
|
if ($record['semi_annually']) {
|
|
array_push($plans, array_merge([
|
|
'name' => 'Semi-Annually',
|
|
'billing_period' => 6,
|
|
'billing_unit' => 'month',
|
|
'price' => [
|
|
'price' => $record['semi_annually'],
|
|
'setup_fee' => $record['semi_annually_setup'],
|
|
'currency_code' => $this->currency_code,
|
|
],
|
|
], $common_fields));
|
|
}
|
|
|
|
if ($record['annually']) {
|
|
array_push($plans, array_merge([
|
|
'name' => 'Annually',
|
|
'billing_period' => 1,
|
|
'billing_unit' => 'year',
|
|
'price' => [
|
|
'price' => $record['annually'],
|
|
'setup_fee' => $record['annually_setup'],
|
|
'currency_code' => $this->currency_code,
|
|
],
|
|
], $common_fields));
|
|
}
|
|
|
|
if ($record['biennially']) {
|
|
array_push($plans, array_merge([
|
|
'name' => 'Biennially',
|
|
'billing_period' => 2,
|
|
'billing_unit' => 'year',
|
|
'price' => [
|
|
'price' => $record['biennially'],
|
|
'setup_fee' => $record['biennially_setup'],
|
|
'currency_code' => $this->currency_code,
|
|
],
|
|
], $common_fields));
|
|
}
|
|
|
|
if ($record['triennially']) {
|
|
array_push($plans, array_merge([
|
|
'name' => 'Triennially',
|
|
'billing_period' => 3,
|
|
'billing_unit' => 'year',
|
|
'price' => [
|
|
'price' => $record['triennially'],
|
|
'setup_fee' => $record['triennially_setup'],
|
|
'currency_code' => $this->currency_code,
|
|
],
|
|
], $common_fields));
|
|
}
|
|
|
|
$all_prices = [];
|
|
foreach ($plans as $plan) {
|
|
$price = $plan['price'];
|
|
// Unset the price from the plan array, so it can be inserted without errors
|
|
unset($plan['price']);
|
|
$plan_id = DB::table('plans')->insertGetId($plan);
|
|
$all_prices[] = array_merge([
|
|
'plan_id' => $plan_id,
|
|
], $price);
|
|
}
|
|
DB::table('prices')->insert($all_prices);
|
|
|
|
continue;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
protected function migrateConfigOptionProducts()
|
|
{
|
|
$this->info('Migrating Config option products...');
|
|
|
|
$this->migrateInBatch('configurable_options', 'SELECT c.id, c.name, c.type, c.order, c.hidden, c.group_id, g.name AS group_name, g.description AS group_description, g.products, c.created_at, c.updated_at FROM configurable_options as c JOIN configurable_option_groups as g ON c.group_id = g.id LIMIT :limit OFFSET :offset', function ($records) {
|
|
$config_option_products = [];
|
|
foreach ($records as $record) {
|
|
|
|
$products = json_decode($record['products']);
|
|
|
|
foreach ($products as $product_id) {
|
|
$config_option_products[] = [
|
|
'config_option_id' => $record['id'],
|
|
'product_id' => (int) $product_id,
|
|
];
|
|
}
|
|
}
|
|
|
|
DB::table('config_option_products')->insert($config_option_products);
|
|
});
|
|
}
|
|
|
|
protected function migrateExtensions()
|
|
{
|
|
$this->info('Migrating Extensions...');
|
|
$stmt = $this->pdo->query('SELECT * FROM extensions');
|
|
$records = $stmt->fetchAll();
|
|
|
|
$extensions = [];
|
|
foreach ($records as $record) {
|
|
try {
|
|
$extension = ExtensionHelper::getExtension($record['type'], $record['name']);
|
|
} catch (Throwable $th) {
|
|
$ext_name = $record['name'];
|
|
$this->warn("Not Migrating '$ext_name', Error: " . $th->getMessage());
|
|
|
|
continue;
|
|
}
|
|
|
|
$extensions[] = [
|
|
'id' => $record['id'],
|
|
'name' => $record['display_name'] ?? $record['name'],
|
|
'extension' => $record['name'],
|
|
'type' => $record['type'],
|
|
'enabled' => $record['enabled'],
|
|
];
|
|
|
|
$stmt = $this->pdo->prepare('SELECT * FROM extension_settings WHERE `extension_id` = :id');
|
|
$stmt->bindValue(':id', $record['id']);
|
|
$stmt->execute();
|
|
$old_ext_settings = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
$ext_name = $record['name'];
|
|
$ext_type = $record['type'];
|
|
|
|
try {
|
|
$extension_cfg = ExtensionHelper::getConfig($ext_type, $ext_name);
|
|
} catch (Throwable $th) {
|
|
$this->warn("Error while getting Extension '$ext_name', Not migrating ext settings: " . $th->getMessage());
|
|
|
|
continue;
|
|
}
|
|
|
|
$extension_settings = [];
|
|
foreach ($old_ext_settings as $old_ext_setting) {
|
|
|
|
// If a setting was renamed in v1, you can probably put the old and new one here
|
|
// the migrator may be able to move that setting
|
|
$old_ext_setting['key'] = match (strtolower($old_ext_setting['key'])) {
|
|
'apikey' => 'api_key',
|
|
default => $old_ext_setting['key'],
|
|
};
|
|
|
|
$setting = array_filter($extension_cfg, fn ($ext) => $ext['name'] == $old_ext_setting['key']);
|
|
$setting = array_merge(...$setting);
|
|
|
|
// Check if the extension wants the setting to be encrypted or not
|
|
if ($setting['encrypted'] ?? false) {
|
|
try {
|
|
// Check if the setting was already encrypted, if yes don't change it
|
|
Crypt::decryptString($old_ext_setting['value']);
|
|
} catch (Throwable $th) {
|
|
// Else, encrypt it
|
|
$old_ext_setting['value'] = Crypt::encryptString($old_ext_setting['value']);
|
|
}
|
|
} else {
|
|
try {
|
|
$decrypted = Crypt::decryptString($old_ext_setting['value']);
|
|
// If the setting was encrypted, decrypted it
|
|
$old_ext_setting['value'] = $decrypted;
|
|
} catch (Throwable $th) {
|
|
// Else, do nothing
|
|
}
|
|
}
|
|
|
|
$extension_settings[] = [
|
|
'key' => $old_ext_setting['key'],
|
|
'value' => $old_ext_setting['value'],
|
|
'type' => $setting['database_type'] ?? 'string',
|
|
'settingable_type' => 'App\Models\Server',
|
|
'settingable_id' => $old_ext_setting['extension_id'],
|
|
'encrypted' => $setting['encrypted'] ?? false,
|
|
'created_at' => $old_ext_setting['created_at'],
|
|
'updated_at' => $old_ext_setting['updated_at'],
|
|
];
|
|
}
|
|
|
|
DB::table('settings')->insert($extension_settings);
|
|
}
|
|
|
|
DB::table('extensions')->insert($extensions);
|
|
$this->info('Done.');
|
|
}
|
|
|
|
protected function migrateProducts()
|
|
{
|
|
$this->info('Migrating Products...');
|
|
$this->migrateInBatch('products', 'SELECT * FROM products LIMIT :limit OFFSET :offset', function ($records) {
|
|
$records = array_map(function ($record) {
|
|
return [
|
|
'id' => $record['id'],
|
|
'name' => $record['name'],
|
|
'slug' => Str::slug($record['name']),
|
|
'description' => $record['description'],
|
|
|
|
'category_id' => $record['category_id'],
|
|
'image' => $record['image'],
|
|
'stock' => $record['stock_enabled'] ? $record['stock'] : null,
|
|
'per_user_limit' => $record['limit'],
|
|
'allow_quantity' => match ($record['allow_quantity']) {
|
|
0 => 'disabled',
|
|
1 => 'separated',
|
|
2 => 'combined',
|
|
default => 'disabled'
|
|
},
|
|
'server_id' => $record['extension_id'],
|
|
|
|
'created_at' => $record['created_at'],
|
|
'updated_at' => $record['updated_at'],
|
|
];
|
|
}, $records);
|
|
|
|
DB::table('products')->insert($records);
|
|
});
|
|
|
|
$this->info('Migrating Product Settings...');
|
|
$this->migrateInBatch('product_settings', 'SELECT * FROM product_settings LIMIT :limit OFFSET :offset', function ($product_settings) {
|
|
|
|
$records = [];
|
|
foreach ($product_settings as $record) {
|
|
try {
|
|
$extension = Server::findOrFail($record['extension']);
|
|
} catch (Throwable $th) {
|
|
$extension = $record['extension'];
|
|
$this->warn("Error while getting Extension '$extension', Not migrating ext product settings: " . $th->getMessage());
|
|
|
|
continue;
|
|
}
|
|
|
|
$migratedOption = ExtensionHelper::call($extension, 'migrateOption', [
|
|
'key' => $record['name'],
|
|
'value' => $record['value'],
|
|
], mayFail: true);
|
|
$records[] = [
|
|
'key' => $migratedOption['key'] ?? $record['name'],
|
|
'value' => $migratedOption['value'] ?? $record['value'],
|
|
'type' => $migratedOption['type'] ?? 'string',
|
|
'settingable_type' => 'App\Models\Product',
|
|
'settingable_id' => $record['product_id'],
|
|
'encrypted' => $migratedOption['encrypted'] ?? false,
|
|
'created_at' => $record['created_at'],
|
|
'updated_at' => $record['updated_at'],
|
|
];
|
|
}
|
|
DB::table('settings')->insert($records);
|
|
});
|
|
}
|
|
|
|
protected function migrateProductUpgrades()
|
|
{
|
|
$this->info('Migrating Product Upgrades...');
|
|
|
|
$this->migrateInBatch(
|
|
'product_upgrades',
|
|
'SELECT * FROM `product_upgrades` LIMIT :limit OFFSET :offset',
|
|
function ($records) {
|
|
$records = array_map(function ($record) {
|
|
return [
|
|
'id' => $record['id'],
|
|
'product_id' => $record['product_id'],
|
|
'upgrade_id' => $record['upgrade_product_id'],
|
|
|
|
'created_at' => $record['created_at'],
|
|
'updated_at' => $record['updated_at'],
|
|
];
|
|
}, $records);
|
|
|
|
DB::table('product_upgrades')->insert($records);
|
|
}
|
|
);
|
|
}
|
|
|
|
protected function migrateServiceCancellations()
|
|
{
|
|
$this->info('Migrating Service Cancellations...');
|
|
|
|
$this->migrateInBatch(
|
|
'cancellations',
|
|
'SELECT cancellations.*, order_products.status as service_status
|
|
FROM `cancellations`
|
|
LEFT JOIN `order_products` ON cancellations.order_product_id = order_products.id LIMIT :limit OFFSET :offset',
|
|
function ($records) {
|
|
|
|
$cancellations = [];
|
|
foreach ($records as $record) {
|
|
if ($record['service_status'] === 'cancelled') {
|
|
continue;
|
|
}
|
|
|
|
$cancellations[] = [
|
|
'id' => $record['id'],
|
|
'service_id' => $record['order_product_id'],
|
|
'reason' => $record['reason'],
|
|
'type' => 'end_of_period',
|
|
'created_at' => $record['created_at'],
|
|
'updated_at' => $record['updated_at'],
|
|
];
|
|
}
|
|
|
|
DB::table('service_cancellations')->insert($cancellations);
|
|
}
|
|
);
|
|
}
|
|
|
|
protected function migrateInvoices()
|
|
{
|
|
$this->info('Migrating Invoices, Invoice Items, and Invoice Transactions...');
|
|
|
|
$this->migrateInBatch('invoices', 'SELECT * FROM invoices LIMIT :limit OFFSET :offset', function ($records) {
|
|
$invoice_ids = implode(',', array_column($records, 'id'));
|
|
$items_stmt = $this->pdo->prepare("SELECT
|
|
invoice_items.*,
|
|
order_products.id as service_id,
|
|
order_products.quantity as service_quantity
|
|
FROM
|
|
invoice_items
|
|
LEFT JOIN
|
|
order_products ON invoice_items.product_id = order_products.id
|
|
WHERE invoice_id IN($invoice_ids)
|
|
");
|
|
$items_stmt->execute();
|
|
$invoice_items_db = $items_stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
$invoice_transactions = [];
|
|
$invoice_items = [];
|
|
|
|
$invoices = array_map(function ($record) use ($invoice_items_db, &$invoice_items, &$invoice_transactions) {
|
|
$transaction_amount = 0;
|
|
|
|
$items = array_map(function ($item) use (&$transaction_amount) {
|
|
|
|
$price = number_format((float) $item['total'], 2, '.', '');
|
|
$transaction_amount += (float) $price;
|
|
|
|
return [
|
|
'id' => $item['id'],
|
|
'invoice_id' => $item['invoice_id'],
|
|
'description' => $item['description'],
|
|
'price' => number_format((float) $item['total'], 2, '.', ''),
|
|
'quantity' => $item['service_quantity'] ?? 1,
|
|
|
|
'reference_type' => 'App\Models\Service',
|
|
'reference_id' => $item['service_id'],
|
|
|
|
'created_at' => $item['created_at'],
|
|
'updated_at' => $item['updated_at'],
|
|
];
|
|
}, array_filter($invoice_items_db, function ($item) use ($record) {
|
|
return $item['invoice_id'] === $record['id'];
|
|
}));
|
|
|
|
// Add the transaction details to invoice_transactions
|
|
if ($transaction_amount > 0 && $record['status'] === 'paid') {
|
|
$gateway = Gateway::where('name', $record['paid_with'])->get()->first();
|
|
$invoice_transactions[] = [
|
|
'invoice_id' => $record['id'],
|
|
'transaction_id' => $record['paid_reference'],
|
|
'gateway_id' => $gateway ? $gateway->id : null,
|
|
'amount' => $transaction_amount,
|
|
'fee' => null,
|
|
|
|
'created_at' => $record['created_at'],
|
|
'updated_at' => $record['updated_at'],
|
|
];
|
|
}
|
|
|
|
// Add the invoice items to invoice_items
|
|
$invoice_items = array_merge($invoice_items, $items);
|
|
|
|
return [
|
|
'id' => $record['id'],
|
|
'number' => $record['id'],
|
|
'status' => $record['status'],
|
|
'due_at' => $record['due_date'],
|
|
'currency_code' => $this->currency_code,
|
|
'user_id' => $record['user_id'],
|
|
|
|
'created_at' => $record['created_at'],
|
|
'updated_at' => $record['updated_at'],
|
|
];
|
|
}, $records);
|
|
|
|
DB::table('invoices')->insert($invoices);
|
|
DB::table('invoice_items')->insert($invoice_items);
|
|
DB::table('invoice_transactions')->insert($invoice_transactions);
|
|
|
|
});
|
|
// Update settings for invoice number
|
|
DB::table('settings')->updateOrInsert(
|
|
['key' => 'invoice_number'],
|
|
['value' => DB::table('invoices')->max('id') ?: 0]
|
|
);
|
|
}
|
|
|
|
protected function migratePlans()
|
|
{
|
|
$this->info('Migrating Plans and Prices...');
|
|
|
|
$stmt = $this->pdo->query('SELECT * FROM product_price');
|
|
$records = $stmt->fetchAll();
|
|
|
|
$plans = [];
|
|
|
|
foreach ($records as $record) {
|
|
|
|
$common_fields = [
|
|
'type' => $record['type'],
|
|
'priceable_id' => $record['product_id'],
|
|
'priceable_type' => 'App\Models\Product',
|
|
];
|
|
|
|
if ($record['monthly']) {
|
|
array_push($plans, array_merge([
|
|
'name' => 'Monthly',
|
|
'billing_period' => 1,
|
|
'billing_unit' => 'month',
|
|
'price' => [
|
|
'price' => $record['monthly'],
|
|
'setup_fee' => $record['monthly_setup'],
|
|
'currency_code' => $this->currency_code,
|
|
],
|
|
], $common_fields));
|
|
}
|
|
|
|
if ($record['quarterly']) {
|
|
array_push($plans, array_merge([
|
|
'name' => 'Quarterly',
|
|
'billing_period' => 3,
|
|
'billing_unit' => 'month',
|
|
'price' => [
|
|
'price' => $record['quarterly'],
|
|
'setup_fee' => $record['quarterly_setup'],
|
|
'currency_code' => $this->currency_code,
|
|
],
|
|
], $common_fields));
|
|
}
|
|
|
|
if ($record['semi_annually']) {
|
|
array_push($plans, array_merge([
|
|
'name' => 'Semi-Annually',
|
|
'billing_period' => 6,
|
|
'billing_unit' => 'month',
|
|
'price' => [
|
|
'price' => $record['semi_annually'],
|
|
'setup_fee' => $record['semi_annually_setup'],
|
|
'currency_code' => $this->currency_code,
|
|
],
|
|
], $common_fields));
|
|
}
|
|
|
|
if ($record['annually']) {
|
|
array_push($plans, array_merge([
|
|
'name' => 'Annually',
|
|
'billing_period' => 1,
|
|
'billing_unit' => 'year',
|
|
'price' => [
|
|
'price' => $record['annually'],
|
|
'setup_fee' => $record['annually_setup'],
|
|
'currency_code' => $this->currency_code,
|
|
],
|
|
], $common_fields));
|
|
}
|
|
|
|
if ($record['biennially']) {
|
|
array_push($plans, array_merge([
|
|
'name' => 'Biennially',
|
|
'billing_period' => 2,
|
|
'billing_unit' => 'year',
|
|
'price' => [
|
|
'price' => $record['biennially'],
|
|
'setup_fee' => $record['biennially_setup'],
|
|
'currency_code' => $this->currency_code,
|
|
],
|
|
], $common_fields));
|
|
}
|
|
|
|
if ($record['triennially']) {
|
|
array_push($plans, array_merge([
|
|
'name' => 'Triennially',
|
|
'billing_period' => 3,
|
|
'billing_unit' => 'year',
|
|
'price' => [
|
|
'price' => $record['triennially'],
|
|
'setup_fee' => $record['triennially_setup'],
|
|
'currency_code' => $this->currency_code,
|
|
],
|
|
], $common_fields));
|
|
}
|
|
}
|
|
|
|
$all_prices = [];
|
|
foreach ($plans as $plan) {
|
|
$price = $plan['price'];
|
|
// Unset the price from the plan array, so it can be inserted without errors
|
|
unset($plan['price']);
|
|
$plan_id = DB::table('plans')->insertGetId($plan);
|
|
$all_prices[] = array_merge([
|
|
'plan_id' => $plan_id,
|
|
], $price);
|
|
}
|
|
DB::table('prices')->insert($all_prices);
|
|
|
|
$this->info('Done.');
|
|
}
|
|
|
|
protected function migrateOrdersAndServices()
|
|
{
|
|
$this->info('Migrating Orders...');
|
|
$order_product_details = [];
|
|
|
|
$this->migrateInBatch('orders', 'SELECT * FROM orders LIMIT :limit OFFSET :offset', function ($records) use (&$order_product_details) {
|
|
$records = array_map(function ($record) use (&$order_product_details) {
|
|
$order_product_details[$record['id']] = [
|
|
'coupon_id' => $record['coupon_id'],
|
|
'user_id' => $record['user_id'],
|
|
];
|
|
|
|
return [
|
|
'id' => $record['id'],
|
|
'user_id' => $record['user_id'],
|
|
'currency_code' => $this->currency_code,
|
|
|
|
'created_at' => $record['created_at'],
|
|
'updated_at' => $record['updated_at'],
|
|
];
|
|
}, $records);
|
|
|
|
DB::table('orders')->insert($records);
|
|
});
|
|
|
|
$this->info('Migrating Services...');
|
|
$this->migrateInBatch('order_products', 'SELECT
|
|
op.*,
|
|
opc.value as stripe_subscription_id
|
|
FROM
|
|
order_products op
|
|
LEFT JOIN
|
|
order_products_config opc
|
|
ON op.id = opc.order_product_id
|
|
AND opc.key = \'stripe_subscription_id\'
|
|
LIMIT :limit OFFSET :offset
|
|
', function ($records) use ($order_product_details) {
|
|
$records = array_map(function ($record) use ($order_product_details) {
|
|
$order = $order_product_details[$record['order_id']];
|
|
|
|
$billing = match ($record['billing_cycle']) {
|
|
'monthly' => [
|
|
'type' => 'recurring',
|
|
'unit' => 'month',
|
|
'period' => 1,
|
|
],
|
|
'quarterly' => [
|
|
'type' => 'recurring',
|
|
'unit' => 'month',
|
|
'period' => 3,
|
|
],
|
|
'semi_annually' => [
|
|
'type' => 'recurring',
|
|
'unit' => 'month',
|
|
'period' => 6,
|
|
],
|
|
'annually' => [
|
|
'type' => 'recurring',
|
|
'unit' => 'year',
|
|
'period' => 1,
|
|
],
|
|
'biennially' => [
|
|
'type' => 'recurring',
|
|
'unit' => 'year',
|
|
'period' => 2,
|
|
],
|
|
'triennially' => [
|
|
'type' => 'recurring',
|
|
'unit' => 'year',
|
|
'period' => 3,
|
|
],
|
|
null => $record['price'] === 0 ? [
|
|
'type' => 'free',
|
|
'unit' => null,
|
|
'period' => null,
|
|
] : [
|
|
'type' => 'one-time',
|
|
'unit' => null,
|
|
'period' => null,
|
|
]
|
|
};
|
|
|
|
$price = Price::where('price', $record['price'])
|
|
->whereHas('plan', function ($query) use ($billing) {
|
|
$query->where('priceable_type', 'App\Models\Product')
|
|
->where('type', $billing['type'])
|
|
->where('billing_period', $billing['period'])
|
|
->where('billing_unit', $billing['unit']);
|
|
})->first();
|
|
|
|
if (!$price) {
|
|
// Select the plan where the price doesn't match
|
|
$plan = DB::table('plans')
|
|
->where('priceable_type', 'App\Models\Product')
|
|
->where('type', $billing['type'])
|
|
->where('billing_period', $billing['period'])
|
|
->where('billing_unit', $billing['unit'])
|
|
->first();
|
|
if ($plan) {
|
|
$plan_id = $plan->id;
|
|
} else {
|
|
// If the plan doesn't exist, create it
|
|
$this->warn("Price not found for order_product_id: {$record['id']}, Creating custom plan.");
|
|
$plan_id = DB::table('plans')->insertGetId([
|
|
'name' => "Custom - {$billing['unit']} {$billing['type']}",
|
|
'type' => $billing['type'],
|
|
'billing_period' => $billing['period'],
|
|
'billing_unit' => $billing['unit'],
|
|
'priceable_id' => $record['product_id'],
|
|
'priceable_type' => 'App\Models\Product',
|
|
]);
|
|
|
|
DB::table('prices')->insert([
|
|
'plan_id' => $plan_id,
|
|
'price' => $record['price'],
|
|
'setup_fee' => null,
|
|
'currency_code' => $this->currency_code,
|
|
]);
|
|
}
|
|
}
|
|
|
|
return [
|
|
'id' => $record['id'],
|
|
// Active instead of Paid status, leave rest unchanged
|
|
'status' => match ($record['status']) {
|
|
'paid' => 'active',
|
|
null => 'cancelled',
|
|
default => $record['status']
|
|
},
|
|
'order_id' => $record['order_id'],
|
|
'product_id' => $record['product_id'],
|
|
'user_id' => $order['user_id'],
|
|
'currency_code' => $this->currency_code,
|
|
|
|
'quantity' => $record['quantity'],
|
|
'price' => $record['price'],
|
|
|
|
'plan_id' => $price->plan_id ?? $plan_id,
|
|
'coupon_id' => $order['coupon_id'],
|
|
'expires_at' => $record['expiry_date'],
|
|
'subscription_id' => $record['stripe_subscription_id'],
|
|
'created_at' => $record['created_at'],
|
|
'updated_at' => $record['updated_at'],
|
|
];
|
|
}, $records);
|
|
DB::table('services')->insert($records);
|
|
});
|
|
}
|
|
|
|
protected function migrateServiceConfigs()
|
|
{
|
|
$this->info('Migrating Service Configs...');
|
|
$this->migrateInBatch('order_products_config', 'SELECT * FROM order_products_config LIMIT :limit OFFSET :offset', function ($records) {
|
|
$service_properties = [];
|
|
$service_configs = [];
|
|
foreach ($records as $record) {
|
|
if ($record['key'] === 'stripe_subscription_id') {
|
|
continue;
|
|
}
|
|
if ($record['is_configurable_option'] === 1) {
|
|
$configOption = ConfigOption::whereId($record['key'])->first();
|
|
if (!$configOption) {
|
|
$this->warn("Config option not found for order_product_id: {$record['order_product_id']}, key: {$record['key']}");
|
|
|
|
continue;
|
|
}
|
|
if (in_array($configOption->type, ['text', 'number'])) {
|
|
$service_properties[] = [
|
|
'name' => $record['key'],
|
|
'key' => $record['key'],
|
|
'custom_property_id' => null,
|
|
'model_id' => $record['order_product_id'],
|
|
'model_type' => 'App\Models\Service',
|
|
'value' => $record['value'],
|
|
];
|
|
|
|
continue;
|
|
}
|
|
$service_configs[] = [
|
|
'configurable_type' => 'App\Models\Service',
|
|
'configurable_id' => $record['order_product_id'],
|
|
'config_option_id' => $configOption->id,
|
|
'config_value_id' => $record['value'],
|
|
];
|
|
} else {
|
|
$service_properties[] = [
|
|
'name' => $record['key'],
|
|
'key' => $record['key'],
|
|
'custom_property_id' => null,
|
|
'model_id' => $record['order_product_id'],
|
|
'model_type' => 'App\Models\Service',
|
|
'value' => $record['value'],
|
|
];
|
|
}
|
|
}
|
|
|
|
DB::table('service_configs')->insert($service_configs);
|
|
DB::table('properties')->insert($service_properties);
|
|
});
|
|
}
|
|
|
|
protected function migrateUsers()
|
|
{
|
|
$this->info('Migrating Users...');
|
|
|
|
// Custom Properties for users
|
|
$address = CustomProperty::where('model', 'App\Models\User')->where('key', 'address')->first();
|
|
$city = CustomProperty::where('model', 'App\Models\User')->where('key', 'city')->first();
|
|
$state = CustomProperty::where('model', 'App\Models\User')->where('key', 'state')->first();
|
|
$zip = CustomProperty::where('model', 'App\Models\User')->where('key', 'zip')->first();
|
|
$country = CustomProperty::where('model', 'App\Models\User')->where('key', 'country')->first();
|
|
$phone = CustomProperty::where('model', 'App\Models\User')->where('key', 'phone')->first();
|
|
$companyname = CustomProperty::where('model', 'App\Models\User')->where('key', 'company_name')->first();
|
|
|
|
$this->migrateInBatch('users', 'SELECT * FROM users LIMIT :limit OFFSET :offset', function ($records) use (
|
|
$address,
|
|
$city,
|
|
$state,
|
|
$zip,
|
|
$country,
|
|
$phone,
|
|
$companyname
|
|
) {
|
|
$properties = [];
|
|
$credits = [];
|
|
|
|
$records = array_map(function ($record) use (
|
|
&$properties,
|
|
&$credits,
|
|
$address,
|
|
$city,
|
|
$state,
|
|
$zip,
|
|
$country,
|
|
$phone,
|
|
$companyname
|
|
) {
|
|
// User properties
|
|
if ($record['address']) {
|
|
array_push($properties, [
|
|
'name' => $address->name,
|
|
'key' => $address->key,
|
|
'custom_property_id' => $address->id,
|
|
'model_id' => $record['id'],
|
|
'model_type' => 'App\Models\User',
|
|
'value' => $record['address'],
|
|
]);
|
|
}
|
|
if ($record['city']) {
|
|
array_push($properties, [
|
|
'name' => $city->name,
|
|
'key' => $city->key,
|
|
'custom_property_id' => $city->id,
|
|
'model_id' => $record['id'],
|
|
'model_type' => 'App\Models\User',
|
|
'value' => $record['city'],
|
|
]);
|
|
}
|
|
if ($record['state']) {
|
|
array_push($properties, [
|
|
'name' => $state->name,
|
|
'key' => $state->key,
|
|
'custom_property_id' => $state->id,
|
|
'model_id' => $record['id'],
|
|
'model_type' => 'App\Models\User',
|
|
'value' => $record['state'],
|
|
]);
|
|
}
|
|
if ($record['zip']) {
|
|
array_push($properties, [
|
|
'name' => $zip->name,
|
|
'key' => $zip->key,
|
|
'custom_property_id' => $zip->id,
|
|
'model_id' => $record['id'],
|
|
'model_type' => 'App\Models\User',
|
|
'value' => $record['zip'],
|
|
]);
|
|
}
|
|
if ($record['country']) {
|
|
array_push($properties, [
|
|
'name' => $country->name,
|
|
'key' => $country->key,
|
|
'custom_property_id' => $country->id,
|
|
'model_id' => $record['id'],
|
|
'model_type' => 'App\Models\User',
|
|
'value' => $record['country'],
|
|
]);
|
|
}
|
|
if ($record['phone']) {
|
|
array_push($properties, [
|
|
'name' => $phone->name,
|
|
'key' => $phone->key,
|
|
'custom_property_id' => $phone->id,
|
|
'model_id' => $record['id'],
|
|
'model_type' => 'App\Models\User',
|
|
'value' => $record['phone'],
|
|
]);
|
|
}
|
|
if ($record['companyname']) {
|
|
array_push($properties, [
|
|
'name' => $companyname->name,
|
|
'key' => $companyname->key,
|
|
'custom_property_id' => $companyname->id,
|
|
'model_id' => $record['id'],
|
|
'model_type' => 'App\Models\User',
|
|
'value' => $record['companyname'],
|
|
]);
|
|
}
|
|
if ($record['credits']) {
|
|
array_push($credits, [
|
|
'user_id' => $record['id'],
|
|
'amount' => $record['credits'],
|
|
'currency_code' => $this->currency_code,
|
|
'created_at' => $record['created_at'],
|
|
'updated_at' => $record['updated_at'],
|
|
]);
|
|
}
|
|
|
|
// User Details
|
|
return [
|
|
'id' => $record['id'],
|
|
'first_name' => $record['first_name'],
|
|
'last_name' => $record['last_name'],
|
|
'email' => $record['email'],
|
|
// If the user had admin role, then give him admin, otherwise give no role
|
|
'role_id' => $record['role_id'] === 1 ? 1 : null,
|
|
'email_verified_at' => $record['email_verified_at'],
|
|
'password' => $record['password'],
|
|
'tfa_secret' => $record['tfa_secret'] ? Crypt::encryptString(Crypt::decrypt($record['tfa_secret'])) : null,
|
|
'created_at' => $record['created_at'],
|
|
'updated_at' => $record['updated_at'],
|
|
'remember_token' => $record['remember_token'],
|
|
];
|
|
}, $records);
|
|
|
|
DB::table('users')->insert($records);
|
|
DB::table('properties')->insert($properties);
|
|
DB::table('credits')->insert($credits);
|
|
});
|
|
}
|
|
|
|
protected function migrateTickets()
|
|
{
|
|
$this->info('Migrating Tickets...');
|
|
$this->migrateInBatch('tickets', 'SELECT * FROM tickets LIMIT :limit OFFSET :offset', function ($records) {
|
|
$records = array_map(function ($record) {
|
|
return [
|
|
'id' => $record['id'],
|
|
'subject' => $record['title'],
|
|
'status' => $record['status'],
|
|
'priority' => $record['priority'],
|
|
'department' => null,
|
|
|
|
'assigned_to' => $record['assigned_to'],
|
|
'user_id' => $record['user_id'],
|
|
'service_id' => $record['order_id'],
|
|
|
|
'created_at' => $record['created_at'],
|
|
'updated_at' => $record['updated_at'],
|
|
];
|
|
}, $records);
|
|
|
|
DB::table('tickets')->insert($records);
|
|
});
|
|
}
|
|
|
|
protected function migrateTicketMessages()
|
|
{
|
|
$this->info('Migrating Ticket Messages...');
|
|
$this->migrateInBatch('ticket_messages', 'SELECT * FROM ticket_messages LIMIT :limit OFFSET :offset', function ($records) {
|
|
|
|
$records = array_filter($records, fn ($record) => !is_null($record['message']) && $record['message'] !== '');
|
|
|
|
$records = array_map(function ($record) {
|
|
return [
|
|
'id' => $record['id'],
|
|
'ticket_id' => $record['ticket_id'],
|
|
'user_id' => $record['user_id'],
|
|
'message' => $record['message'],
|
|
|
|
'created_at' => $record['created_at'],
|
|
'updated_at' => $record['updated_at'],
|
|
];
|
|
}, $records);
|
|
|
|
DB::table('ticket_messages')->insert($records);
|
|
});
|
|
}
|
|
|
|
protected function migrateTaxRates()
|
|
{
|
|
$this->info('Migrating Tax Rates...');
|
|
$this->migrateInBatch('tax_rates', 'SELECT * FROM tax_rates LIMIT :limit OFFSET :offset', function ($records) {
|
|
$records = array_map(function ($record) {
|
|
return [
|
|
'id' => $record['id'],
|
|
'name' => $record['name'],
|
|
'rate' => $record['rate'],
|
|
'country' => $record['country'],
|
|
|
|
'created_at' => $record['created_at'],
|
|
'updated_at' => $record['updated_at'],
|
|
];
|
|
}, $records);
|
|
|
|
// Country should be unique
|
|
$records = array_filter($records, function ($record) {
|
|
static $countries = [];
|
|
if (in_array($record['country'], $countries)) {
|
|
$this->error("Duplicate country found: {$record['country']}," .
|
|
" Tax Rate with ID: {$record['id']} will not be migrated.");
|
|
|
|
return false;
|
|
}
|
|
$countries[] = $record['country'];
|
|
|
|
return true;
|
|
});
|
|
|
|
DB::table('tax_rates')->insert($records);
|
|
});
|
|
}
|
|
|
|
protected function migrateCategories()
|
|
{
|
|
$this->info('Migrating Categories...');
|
|
$this->migrateInBatch('categories', 'SELECT * FROM categories LIMIT :limit OFFSET :offset', function ($records) {
|
|
$records = array_map(function ($record) {
|
|
return [
|
|
|
|
'id' => $record['id'],
|
|
'slug' => $record['slug'],
|
|
'name' => $record['name'],
|
|
'description' => $record['description'],
|
|
'image' => $record['image'],
|
|
'parent_id' => $record['category_id'],
|
|
'full_slug' => $record['slug'],
|
|
|
|
'created_at' => $record['created_at'],
|
|
'updated_at' => $record['updated_at'],
|
|
];
|
|
}, $records);
|
|
|
|
DB::table('categories')->insert($records);
|
|
});
|
|
}
|
|
|
|
protected function migrateCoupons()
|
|
{
|
|
$this->info('Migrating Coupons...');
|
|
$this->migrateInBatch('coupons', 'SELECT * FROM coupons LIMIT :limit OFFSET :offset', function ($records) {
|
|
$coupon_products = [];
|
|
|
|
$records = array_map(function ($record) {
|
|
if ($record['products']) {
|
|
foreach (json_decode($record['products']) as $product_id) {
|
|
$coupon_products[] = [
|
|
'coupon_id' => (int) $record['id'],
|
|
'product_id' => (int) $product_id,
|
|
];
|
|
}
|
|
}
|
|
|
|
return [
|
|
'id' => $record['id'],
|
|
|
|
'type' => $record['type'] == 'percent' ? 'percentage' : 'fixed',
|
|
'recurring' => null,
|
|
'code' => $record['code'],
|
|
'value' => number_format((float) $record['value'], 2, '.', ''),
|
|
'max_uses' => (int) $record['max_uses'],
|
|
'starts_at' => $record['start_date'],
|
|
'expires_at' => $record['end_date'],
|
|
|
|
'created_at' => $record['created_at'],
|
|
'updated_at' => $record['updated_at'],
|
|
];
|
|
}, $records);
|
|
|
|
DB::table('coupons')->insert($records);
|
|
DB::table('coupon_products')->insert($coupon_products);
|
|
});
|
|
}
|
|
}
|