2026_10_24_120000_create_member_sharing_system.php 6.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. <?php
  2. use App\Services\Sharing\ShareDefaults;
  3. use Illuminate\Database\Migrations\Migration;
  4. use Illuminate\Database\Schema\Blueprint;
  5. use Illuminate\Support\Facades\DB;
  6. use Illuminate\Support\Facades\Schema;
  7. return new class extends Migration {
  8. public function up(): void
  9. {
  10. Schema::table('share_settings', function (Blueprint $t) {
  11. $t->decimal('valid_member_min_effective_bet', 24, 10)->nullable();
  12. $t->decimal('indirect_bonus_rate', 8, 4)->nullable();
  13. $t->date('activation_date')->nullable();
  14. });
  15. Schema::create('share_policies', function (Blueprint $t) {
  16. $t->id(); $t->date('effective_date')->unique();
  17. $t->boolean('enabled')->default(false); $t->boolean('benefit_enabled')->default(false);
  18. $t->decimal('valid_member_min_deposit', 24, 10)->default(20);
  19. $t->decimal('valid_member_min_effective_bet', 24, 10)->nullable();
  20. $t->decimal('indirect_bonus_rate', 8, 4)->nullable(); $t->json('rules'); $t->timestamps();
  21. });
  22. Schema::create('share_levels', function (Blueprint $t) {
  23. $t->id(); $t->unsignedInteger('level')->unique(); $t->string('name'); $t->string('image', 1000)->default('');
  24. $t->decimal('incremental_commission', 24, 10)->default(0); $t->timestamps();
  25. });
  26. Schema::create('share_members', function (Blueprint $t) {
  27. $t->unsignedBigInteger('user_id')->primary(); $t->unsignedBigInteger('parent_user_id')->nullable()->index();
  28. $t->string('invitation_code', 100)->default(''); $t->string('binding_status', 24)->default('root');
  29. $t->unsignedInteger('level')->default(1); $t->dateTime('bound_at'); $t->timestamps();
  30. });
  31. Schema::create('share_tree', function (Blueprint $t) {
  32. $t->unsignedBigInteger('ancestor_user_id'); $t->unsignedBigInteger('descendant_user_id');
  33. $t->unsignedInteger('depth'); $t->dateTime('bound_at')->default('1970-01-01 00:00:00');
  34. $t->primary(['ancestor_user_id','descendant_user_id']);
  35. $t->index(['descendant_user_id','depth']);
  36. });
  37. Schema::create('share_bet_facts', function (Blueprint $t) {
  38. $t->id(); $t->string('source',32); $t->string('source_id',64); $t->unique(['source','source_id']);
  39. $t->unsignedBigInteger('user_id')->index(); $t->string('member_id',64); $t->string('category',32);
  40. $t->dateTime('bet_at'); $t->date('bet_date')->index(); $t->dateTime('settled_at')->nullable();
  41. foreach (['bet_amount','net_profit','effective_amount'] as $c) $t->decimal($c,24,10)->default(0);
  42. $t->boolean('settled')->default(false); $t->boolean('voided')->default(false);
  43. $t->string('currency',8)->default('CNY'); $t->string('source_version',64); $t->timestamps();
  44. $t->index(['user_id','bet_date','category']);
  45. });
  46. Schema::create('share_accounts', function (Blueprint $t) {
  47. $t->unsignedBigInteger('user_id')->primary();
  48. foreach (['earned_amount','paid_amount','reserved_amount'] as $c) $t->decimal($c,24,10)->default(0);
  49. $t->timestamps();
  50. });
  51. Schema::create('share_settlements', function (Blueprint $t) {
  52. $t->id(); $t->unsignedBigInteger('user_id'); $t->date('bet_date'); $t->string('category',32);
  53. $t->unique(['user_id','bet_date','category']);
  54. foreach (['direct_performance','indirect_performance','direct_commission','indirect_commission'] as $c) $t->decimal($c,24,10)->default(0);
  55. $t->unsignedInteger('valid_direct_members')->default(0); $t->decimal('rate',8,4)->default(0);
  56. $t->decimal('indirect_bonus_rate',8,4)->default(0); $t->unsignedBigInteger('policy_id')->nullable();
  57. $t->unsignedInteger('revision')->default(0); $t->string('input_hash',64)->default(''); $t->timestamps();
  58. });
  59. Schema::create('share_ledger', function (Blueprint $t) {
  60. $t->id(); $t->unsignedBigInteger('user_id')->index(); $t->unsignedBigInteger('settlement_id');
  61. $t->unsignedInteger('revision'); $t->string('type',16); $t->decimal('amount',24,10);
  62. $t->date('bet_date'); $t->string('category',32); $t->timestamps();
  63. $t->unique(['settlement_id','revision','type']);
  64. });
  65. Schema::create('share_claims', function (Blueprint $t) {
  66. $t->id(); $t->unsignedBigInteger('user_id')->index(); $t->string('request_id',64);
  67. $t->unique(['user_id','request_id']); $t->unsignedBigInteger('active_user_id')->nullable()->unique();
  68. $t->decimal('amount',24,10); $t->string('status',16)->default('pending')->index();
  69. $t->unsignedBigInteger('audit_admin_id')->nullable(); $t->text('audit_remark')->nullable();
  70. $t->dateTime('audited_at')->nullable(); $t->unsignedBigInteger('credited_log_id')->nullable(); $t->timestamps();
  71. });
  72. Schema::create('share_system_state', function (Blueprint $t) {
  73. $t->string('key',64)->primary(); $t->text('value'); $t->timestamps();
  74. });
  75. $now = date('Y-m-d H:i:s');
  76. $minimum = DB::table('share_settings')->value('valid_member_min_deposit') ?? 20;
  77. // Legacy benefit_enabled never funded these rules. Explicitly configure and enable the new system.
  78. DB::table('share_settings')->update(['benefit_enabled'=>0]);
  79. DB::table('share_policies')->insert(['effective_date'=>'1970-01-01','enabled'=>0,'benefit_enabled'=>0,
  80. 'valid_member_min_deposit'=>$minimum,'rules'=>json_encode(ShareDefaults::rules()),'created_at'=>$now,'updated_at'=>$now]);
  81. DB::table('share_levels')->insert(['level'=>1,'name'=>'等级1','image'=>'','incremental_commission'=>0,'created_at'=>$now,'updated_at'=>$now]);
  82. DB::table('share_system_state')->insert(['key'=>'relations_lock','value'=>'1','created_at'=>$now,'updated_at'=>$now]);
  83. }
  84. public function down(): void
  85. {
  86. foreach (['share_system_state','share_claims','share_ledger','share_settlements','share_accounts','share_bet_facts','share_tree','share_members','share_levels','share_policies'] as $table) Schema::dropIfExists($table);
  87. Schema::table('share_settings', function (Blueprint $t) { $t->dropColumn(['valid_member_min_effective_bet','indirect_bonus_rate','activation_date']); });
  88. }
  89. };