Prezentare Generală
Sistemul de închiriere domenii funcționează pe baza unui mecanism de licitație în care brokerii licitează pentru dreptul de a închiria un domeniu pentru o perioadă specificată.
🎯 Actori Principali
- Administrator - Gestionează domenii și licitații
- Broker - Licitează pentru domenii
- Subscriber (Abonat) - Folosește domeniul după închiriere
- Sistem Automat (Cron Jobs) - Procesează licitații și facturi
Flux Complet - 7 Faze
FAZA 1
Pregătire Licitație
1.1. Administrator Adaugă Domeniu
Backend → Domenii → Adaugă Domeniu
// Câmpuri obligatorii
Domain:
- name: "exemplu"
- extension: ".ro"
- full_name: "exemplu.ro"
- price: 100.00
- expire_at: "2026-12-31"
- status: ACTIVE
1.2. Administrator Creează Licitație
Backend → Licitații → Adaugă Licitație
| Parametru | Tip | Exemplu | Descriere |
|---|---|---|---|
domain_id |
integer | 1 | ID-ul domeniului pentru care se licitează |
start_at |
datetime | 2025-12-05 00:00:00 | Data început licitație |
end_at |
datetime | 2025-12-20 23:59:59 | Data sfârșit licitație |
start_price |
decimal(10,2) | 100.00 | Prețul minim de pornire |
step |
decimal(10,2) | 5.00 | Pas de incrementare |
valid_from |
datetime | 2026-01-01 00:00:00 | Început perioadă validitate |
valid_to |
datetime | 2026-01-31 23:59:59 | Sfârșit perioadă validitate |
period |
integer | 1 | Perioada de închiriere (1, 3, 6, 12) |
cycle |
string | MONTHLY | Ciclul (MONTHLY, YEARLY) |
currency |
string | RON | Moneda (RON, EUR, USD) |
FAZA 2
Procesul de Licitație
2.1. Broker Vizualizează Licitații Active
Frontend → Domenii cu Licitații Active
// Query pentru licitații active
SELECT * FROM auction
WHERE status = ACTIVE
AND start_at <= NOW()
AND end_at >= NOW()
2.2. Broker Plasează Licitație
Frontend → Click domeniu → Modal "Bid on Domain"
Validări Automate (BidForm.php)
// frontend/modules/domain/models/BidForm.php
// frontend/modules/bid/models/BidForm.php
public function validateBidAmount($attribute, $params)
{
$auction = $this->auction;
$bidAmount = $this->$attribute;
$startPrice = (float)$auction->start_price;
$step = (float)$auction->step;
// Validare 1: Bid >= start_price
if ($bidAmount < $startPrice) {
$this->addError($attribute,
"Minimum bid: {$startPrice}");
return;
}
// Validare 2: Pentru bid-uri ulterioare
$highestBid = Bid::find()
->where(['auction_id' => $auction->id])
->orderBy(['price' => SORT_DESC])
->one();
if ($highestBid && $bidAmount < $highestBid->price + $step) {
$this->addError($attribute,
"Minimum: {$highestBid->price + $step}");
return;
}
// Validare 3: Diferența trebuie să fie multiplu de step
$difference = $bidAmount - $startPrice;
if (fmod($difference, $step) > 0.01) {
$this->addError($attribute,
"Bid must be multiple of step: {$step}");
}
}
✅ Reguli Validare
- Prima licitație:
bid >= start_price - Licitații ulterioare:
bid >= current_price + step - Toate:
(bid - start_price) % step == 0
FAZA 3
Închidere Licitație (Automată)
3.1. Cron Job - Închidere Licitații
php yii auction/run
Frecvență: Zilnic (ex: 00:05)
// console/controllers/AuctionController.php
public function actionRun()
{
$count = 0;
$this->stdout("[" . date('Y-m-d H:i:s') . "] Processing auctions...\n");
// Găsește licitații expirate
$auctions = Auction::find()
->where(['status' => Auction::STATUS_ACTIVE])
->andWhere(['<=', 'end_at', date('Y-m-d H:i:s')])
->all();
foreach ($auctions as $auction) {
// Găsește bid-ul câștigător
$highestBid = Bid::find()
->where(['auction_id' => $auction->id])
->orderBy(['price' => SORT_DESC])
->one();
if ($highestBid) {
// Generează factura proforma
$this->saveProformaInvoice($highestBid, $auction->domain_id);
// Trimite email câștigător
$this->sendBrokerWinnerEmail($highestBid, $auction);
// Update status-uri
$auction->status = Auction::STATUS_PROCESSING;
$auction->save(false);
$highestBid->status = Bid::STATUS_PROCESSING;
$highestBid->save(false);
$count++;
}
}
$this->stdout("[" . date('Y-m-d H:i:s') . "] Processed {$count} auction(s).\n");
}
3.2. Generare Factură Proforma
| Câmp Invoice | Valoare | Descriere |
|---|---|---|
broker_id |
ID broker câștigător | Legătură cu brokerul |
type |
TYPE_PROFORMA (11) |
Tip factură |
status |
STATUS_UNPAID (1) |
Status inițial |
amount |
Prețul licitat | Suma de plată |
currency |
RON / EUR / USD | Moneda |
issued_at |
NOW() | Data emitere |
3.3. Email Notificare Câștigător
Template: EMAIL_VARIANT_DOMAIN_WIN
ShortCodes disponibile:
{{DOMAIN_FULL_NAME}}- Numele complet al domeniului{{PRICE}}- Prețul licitat{{DAYS_TO_RESPOND}}- Numărul de zile pentru plată (default: 2){{INVOICE_URL_LINK}}- Link către factura proforma
FAZA 4
Plata Facturii Proforma
4.1. Broker Accesează Factura
Frontend → My Account → Invoices
- Vizualizează factura proforma
- Descarcă PDF (cu watermark "UNPAID")
- Vede detalii: domeniu, preț, TVA, total
4.2. Confirmare Plată
// Manual (Admin confirmă)
Backend → Invoices → Marchează ca plătită
// Automat (Webhook procesator plată)
$invoice->status = Invoice::STATUS_PAID;
$invoice->paid_at = date('Y-m-d H:i:s');
$invoice->save();
FAZA 5
Transfer la Următorul Broker
5.1. Cron Job - Verificare Plăți
php yii next-broker/run
Frecvență: Zilnic (ex: 00:10)
// console/controllers/NextBrokerController.php
public function actionRun()
{
$count = 0;
$transferredCount = 0;
$noOfDays = 2; // Configurabil
$this->stdout("[" . date('Y-m-d H:i:s') . "] Checking unpaid auctions...\n");
// Găsește licitații cu facturi neplătite > 2 zile
$auctions = Auction::find()
->where(['status' => Auction::STATUS_PROCESSING])
->all();
foreach ($auctions as $auction) {
$bid = Bid::find()
->where([
'auction_id' => $auction->id,
'status' => Bid::STATUS_PROCESSING
])
->one();
if (!$bid) continue;
// Verifică factura
$invoice = Invoice::findOne([
'broker_id' => $bid->broker_id,
'status' => Invoice::STATUS_UNPAID
]);
if (!$invoice) continue;
// Verifică dacă au trecut 2 zile
$issuedDate = new DateTime($invoice->issued_at);
$currentDate = new DateTime();
$daysPassed = $currentDate->diff($issuedDate)->days;
if ($daysPassed >= $noOfDays) {
$count++;
// Dezactivează bid-ul curent
$bid->status = Bid::STATUS_INACTIVE;
$bid->save(false);
// Găsește următorul bid
$nextBid = Bid::find()
->where([
'auction_id' => $auction->id,
'status' => Bid::STATUS_ACTIVE
])
->orderBy(['price' => SORT_DESC])
->one();
if ($nextBid) {
// Generează nouă factură proforma
$this->saveProformaInvoice($nextBid, $auction->domain_id);
// Trimite email
$this->sendBrokerWinnerEmail($nextBid, $auction);
// Update status
$nextBid->status = Bid::STATUS_PROCESSING;
$nextBid->save(false);
$transferredCount++;
}
}
}
$this->stdout("[" . date('Y-m-d H:i:s') . "] Processed {$count} unpaid auction(s), transferred {$transferredCount} to next broker(s).\n");
}
FAZA 6
Activare Închiriere
6.1. Creare Abonament (După Plată)
// Creare subscription după confirmare plată
$subscription = new Subscription();
$subscription->subscriber_id = $broker->id;
$subscription->domain_id = $auction->domain_id;
$subscription->start_at = $auction->valid_from;
$subscription->end_at = $auction->valid_to;
$subscription->price = $bid->price;
$subscription->currency = $auction->currency;
$subscription->status = Subscription::STATUS_ACTIVE;
$subscription->save();
6.2. Email Confirmare Plată
Template: EMAIL_VARIANT_INVOICE_PAYMENT_CONFIRMATION
Conține:
- Confirmare plată primită
- Detalii domeniu și perioadă
- Factura finală (PDF fără watermark)
- Instrucțiuni acces domeniu
FAZA 7
Monitorizare și Reînnoire
7.1. Cron Job - Verificare Abonamente
php yii payment/run
Frecvență: Zilnic (ex: 00:15)
- Verifică abonamente care se apropie de expirare
- Generează facturi pentru reînnoire
- Trimite notificări (X zile înainte)
- Suspendă abonamente neplătite
Statusuri și Tranzițiile Lor
Auction (Licitație)
STATUS_ACTIVE (0)
↓ (când end_at <= NOW)
↓ [php yii auction/run]
STATUS_PROCESSING (2)
↓ (după plată și creare subscription)
STATUS_INACTIVE (1)
Bid (Licitație Broker)
STATUS_ACTIVE (0)
↓ (când auction se închide și este câștigător)
↓ [php yii auction/run]
STATUS_PROCESSING (2)
↓ (dacă NU plătește în 2 zile)
↓ [php yii next-broker/run]
STATUS_INACTIVE (1)
Invoice (Factură)
TYPE_PROFORMA (11) + STATUS_UNPAID (1)
↓ (broker plătește)
STATUS_PAID (2)
↓ (sistem generează factura finală)
TYPE_INVOICE (10) + STATUS_PAID (2)
Comenzi Console (Cron Jobs)
| Comandă | Frecvență | Descriere | Output |
|---|---|---|---|
php yii auction/run |
Zilnic 00:05 | Închide licitații expirate Generează proforma Trimite emailuri |
[timestamp] Processed X auction(s). |
php yii next-broker/run |
Zilnic 00:10 | Verifică facturi neplătite Transferă la următorul broker |
[timestamp] Processed X unpaid, transferred Y. |
php yii payment/run |
Zilnic 00:15 | Verifică abonamente Generează facturi reînnoire |
[timestamp] Processed X subscription(s). |
php yii subscription/renew-features-quota |
Lunar (1 ale lunii) | Resetează quota features | [timestamp] Renewed features quota. |
Setup Cron Jobs (Recomandări)
# Închidere licitații
5 0 * * * cd /path/to/app && php yii auction/run >> /var/log/auction.log 2>&1
# Transfer la următorul broker
10 0 * * * cd /path/to/app && php yii next-broker/run >> /var/log/next-broker.log 2>&1
# Verificare plăți abonamente
15 0 * * * cd /path/to/app && php yii payment/run >> /var/log/payment.log 2>&1
# Reînnoire quota features (lunar)
0 0 1 * * cd /path/to/app && php yii subscription/renew-features-quota >> /var/log/subscription.log 2>&1
Structura Bazei de Date
Tabele Principale
| Tabelă | Câmpuri Cheie | Relații |
|---|---|---|
domain |
id, name, extension, full_name, price, expire_at, status | hasMany Auction, hasMany Subscription |
auction |
id, domain_id, start_at, end_at, start_price, step, valid_from, valid_to, status | belongsTo Domain, hasMany Bid |
bid |
id, auction_id, broker_id, price, currency, status | belongsTo Auction, belongsTo Broker |
invoice |
id, broker_id, type, status, amount, issued_at, paid_at | belongsTo Broker, hasMany Item |
item |
id, invoice_id, item_id, type, quantity, price | belongsTo Invoice |
subscription |
id, subscriber_id, domain_id, start_at, end_at, price, status | belongsTo Domain, belongsTo Subscriber |
Troubleshooting
⚠️ Problema: Factura nu se generează
- Verifică template-ul de factură în backend
- Verifică că există
Template::TYPE_INVOICE - Check logs pentru erori SQL:
@runtime/logs/app.log
⚠️ Problema: Email-ul nu se trimite
- Verifică configurarea SMTP în
common/config/main-local.php - Verifică template-ul email în backend
- Test SMTP:
php yii test/email - Check mailer component configuration
⚠️ Problema: Cron job nu rulează
- Verifică crontab:
crontab -l - Check permissions:
chmod +x yii - Verifică path-ul către PHP:
which php - Check logs:
tail -f /var/log/auction.log
API Endpoints (Dacă există)
📡 REST API (Opțional)
// Listare licitații active
GET /api/v1/auctions?status=active
// Plasare bid
POST /api/v1/bids
{
"auction_id": 1,
"price": 150.00,
"currency": "RON"
}
// Verificare status licitație
GET /api/v1/auctions/{id}/status
// Istoric bid-uri
GET /api/v1/auctions/{id}/bids
📞 Suport Tehnic
Pentru probleme tehnice sau întrebări despre implementare, contactează echipa de dezvoltare.
📅 Generat: 17 Decembrie 2025 | ⚙️ Yii2 Advanced Framework