owner and admin section
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Crea le tabelle per gli abbonamenti dei saloni:
|
||||
* - subscription_plans: i piani disponibili (gestiti dall'admin)
|
||||
* - shop_subscriptions: l'abbonamento corrente di ogni salone
|
||||
*
|
||||
* Modello: l'abbonamento è il "motore" che accende/spegne shops.active.
|
||||
* expires_at è la data chiave: superata, il cron mette status=expired e spegne il salone.
|
||||
*/
|
||||
class CreateSubscriptions extends AbstractMigration
|
||||
{
|
||||
public function change(): void
|
||||
{
|
||||
// ---- subscription_plans ----
|
||||
$plans = $this->table('subscription_plans', [
|
||||
'id' => false,
|
||||
'primary_key' => ['id'],
|
||||
'engine' => 'InnoDB',
|
||||
'encoding' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
]);
|
||||
|
||||
$plans
|
||||
->addColumn('id', 'integer', ['identity' => true, 'signed' => false])
|
||||
->addColumn('name', 'string', ['limit' => 80])
|
||||
->addColumn('description', 'string', ['limit' => 255, 'null' => true])
|
||||
->addColumn('price', 'decimal', ['precision' => 8, 'scale' => 2, 'default' => '0.00'])
|
||||
->addColumn('billing_period', 'enum', ['values' => ['monthly', 'yearly'], 'default' => 'monthly'])
|
||||
->addColumn('stripe_price_id', 'string', ['limit' => 120, 'null' => true])
|
||||
->addColumn('is_active', 'boolean', ['default' => true])
|
||||
->addColumn('created_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP', 'null' => true])
|
||||
->addColumn('updated_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP', 'update' => 'CURRENT_TIMESTAMP', 'null' => true])
|
||||
->create();
|
||||
|
||||
// ---- shop_subscriptions ----
|
||||
$subs = $this->table('shop_subscriptions', [
|
||||
'id' => false,
|
||||
'primary_key' => ['id'],
|
||||
'engine' => 'InnoDB',
|
||||
'encoding' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
]);
|
||||
|
||||
$subs
|
||||
->addColumn('id', 'biginteger', ['identity' => true, 'signed' => false])
|
||||
->addColumn('shop_id', 'biginteger', ['signed' => false])
|
||||
->addColumn('plan_id', 'integer', ['signed' => false, 'null' => true])
|
||||
->addColumn('status', 'enum', [
|
||||
'values' => ['active', 'expired', 'blocked', 'trialing', 'pending'],
|
||||
'default' => 'pending',
|
||||
])
|
||||
->addColumn('started_at', 'date', ['null' => true])
|
||||
->addColumn('expires_at', 'date', ['null' => true])
|
||||
->addColumn('block_reason', 'string', ['limit' => 255, 'null' => true])
|
||||
->addColumn('stripe_customer_id', 'string', ['limit' => 120, 'null' => true])
|
||||
->addColumn('stripe_subscription_id', 'string', ['limit' => 120, 'null' => true])
|
||||
->addColumn('created_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP', 'null' => true])
|
||||
->addColumn('updated_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP', 'update' => 'CURRENT_TIMESTAMP', 'null' => true])
|
||||
->addIndex(['shop_id'], ['unique' => true, 'name' => 'uniq_shop'])
|
||||
->addIndex(['status'], ['name' => 'idx_status'])
|
||||
->addIndex(['expires_at'], ['name' => 'idx_expires'])
|
||||
->addForeignKey('shop_id', 'shops', 'id', ['delete' => 'CASCADE', 'update' => 'NO_ACTION', 'constraint' => 'fk_sub_shop'])
|
||||
->addForeignKey('plan_id', 'subscription_plans', 'id', ['delete' => 'SET_NULL', 'update' => 'NO_ACTION', 'constraint' => 'fk_sub_plan'])
|
||||
->create();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Tabella billing_profiles: dati fiscali per la fatturazione degli abbonamenti.
|
||||
* Legata sia all'utente (chi paga) sia al salone (per cosa), così regge
|
||||
* anche il caso futuro di un owner con più saloni e P.IVA diverse.
|
||||
*/
|
||||
class CreateBillingProfiles extends AbstractMigration
|
||||
{
|
||||
public function change(): void
|
||||
{
|
||||
$t = $this->table('billing_profiles', [
|
||||
'id' => false,
|
||||
'primary_key' => ['id'],
|
||||
'engine' => 'InnoDB',
|
||||
'encoding' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
]);
|
||||
|
||||
$t
|
||||
->addColumn('id', 'biginteger', ['identity' => true, 'signed' => false])
|
||||
->addColumn('user_id', 'integer', ['signed' => false])
|
||||
->addColumn('shop_id', 'biginteger', ['signed' => false, 'null' => true])
|
||||
->addColumn('business_name', 'string', ['limit' => 191])
|
||||
->addColumn('vat_number', 'string', ['limit' => 20])
|
||||
->addColumn('tax_code', 'string', ['limit' => 20, 'null' => true])
|
||||
->addColumn('address', 'string', ['limit' => 255])
|
||||
->addColumn('zip_code', 'string', ['limit' => 10])
|
||||
->addColumn('city', 'string', ['limit' => 100])
|
||||
->addColumn('province', 'string', ['limit' => 50, 'null' => true])
|
||||
->addColumn('pec', 'string', ['limit' => 191, 'null' => true])
|
||||
->addColumn('sdi_code', 'string', ['limit' => 7, 'null' => true])
|
||||
->addColumn('created_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP', 'null' => true])
|
||||
->addColumn('updated_at', 'timestamp', ['default' => 'CURRENT_TIMESTAMP', 'update' => 'CURRENT_TIMESTAMP', 'null' => true])
|
||||
->addIndex(['user_id'], ['name' => 'idx_bp_user'])
|
||||
->addIndex(['shop_id'], ['name' => 'idx_bp_shop'])
|
||||
->addForeignKey('user_id', 'auth_users', 'id', ['delete' => 'CASCADE', 'update' => 'NO_ACTION', 'constraint' => 'fk_bp_user'])
|
||||
->addForeignKey('shop_id', 'shops', 'id', ['delete' => 'SET_NULL', 'update' => 'NO_ACTION', 'constraint' => 'fk_bp_shop'])
|
||||
->create();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Aggiunge il campo "target" (pubblico servito) a shops, staff e services.
|
||||
* Tipo SET MySQL: si possono selezionare più valori insieme (es. 'uomo,donna').
|
||||
* Valori: uomo, donna, bambino, unisex.
|
||||
*
|
||||
* Scelta SET vs tabelle di collegamento: le categorie sono 4, fisse e senza
|
||||
* attributi propri, quindi il SET è più semplice e filtrabile con FIND_IN_SET()
|
||||
* senza JOIN aggiuntive. Nota logica (da applicare in ricerca): "unisex" copre
|
||||
* sia uomo che donna.
|
||||
*/
|
||||
class AddTargetAudience extends AbstractMigration
|
||||
{
|
||||
public function change(): void
|
||||
{
|
||||
$values = "'uomo','donna','bambino','unisex'";
|
||||
|
||||
// shops: default unisex (un salone di norma serve tutti finché non specifica)
|
||||
$this->execute("
|
||||
ALTER TABLE `shops`
|
||||
ADD COLUMN `target` SET($values) NOT NULL DEFAULT 'unisex'
|
||||
AFTER `description`
|
||||
");
|
||||
|
||||
// staff: chi tratta cosa. Default unisex.
|
||||
$this->execute("
|
||||
ALTER TABLE `staff`
|
||||
ADD COLUMN `target` SET($values) NOT NULL DEFAULT 'unisex'
|
||||
AFTER `role`
|
||||
");
|
||||
|
||||
// services: a chi è rivolto il servizio. Default unisex.
|
||||
$this->execute("
|
||||
ALTER TABLE `services`
|
||||
ADD COLUMN `target` SET($values) NOT NULL DEFAULT 'unisex'
|
||||
AFTER `category`
|
||||
");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
use Phinx\Seed\AbstractSeed;
|
||||
|
||||
/**
|
||||
* Inserisce due piani base d'esempio.
|
||||
* I prezzi/nome sono modificabili poi dal pannello admin o ri-eseguendo il seed.
|
||||
* stripe_price_id resta NULL: lo popoleremo quando colleghiamo Stripe.
|
||||
*/
|
||||
class SubscriptionPlansSeeder extends AbstractSeed
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
// Evita duplicati se il seed viene rilanciato: inserisce solo se la tabella è vuota
|
||||
$count = (int)$this->fetchRow("SELECT COUNT(*) AS c FROM subscription_plans")['c'];
|
||||
if ($count > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = [
|
||||
[
|
||||
'name' => 'Base',
|
||||
'description' => 'Prenotazioni online, agenda e gestione clienti.',
|
||||
'price' => 19.90,
|
||||
'billing_period' => 'monthly',
|
||||
'is_active' => 1,
|
||||
],
|
||||
[
|
||||
'name' => 'Pro',
|
||||
'description' => 'Tutto del piano Base + più staff, statistiche e priorità in ricerca.',
|
||||
'price' => 39.90,
|
||||
'billing_period' => 'monthly',
|
||||
'is_active' => 1,
|
||||
],
|
||||
];
|
||||
|
||||
$this->table('subscription_plans')->insert($data)->saveData();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user