Changeset View
Changeset View
Standalone View
Standalone View
src/app/Transaction.php
<?php | <?php | ||||
namespace App; | namespace App; | ||||
use App\Entitlement; | |||||
use App\Wallet; | |||||
use Illuminate\Database\Eloquent\Model; | use Illuminate\Database\Eloquent\Model; | ||||
/** | /** | ||||
* The eloquent definition of a Transaction. | * The eloquent definition of a Transaction. | ||||
* | * | ||||
* @property int $amount | * @property int $amount | ||||
* @property string $description | * @property string $description | ||||
* @property string $id | * @property string $id | ||||
* @property string $object_id | * @property string $object_id | ||||
* @property string $object_type | * @property string $object_type | ||||
* @property string $type | * @property string $type | ||||
* @property string $transaction_id | * @property string $transaction_id | ||||
* @property string $user_email | * @property string $user_email | ||||
*/ | */ | ||||
class Transaction extends Model | class Transaction extends Model | ||||
{ | { | ||||
public const ENTITLEMENT_BILLED = 'billed'; | |||||
public const ENTITLEMENT_CREATED = 'created'; | |||||
public const ENTITLEMENT_DELETED = 'deleted'; | |||||
public const WALLET_AWARD = 'award'; | |||||
public const WALLET_CREDIT = 'credit'; | |||||
public const WALLET_DEBIT = 'debit'; | |||||
public const WALLET_PENALTY = 'penalty'; | |||||
protected $fillable = [ | protected $fillable = [ | ||||
// actor, if any | // actor, if any | ||||
'user_email', | 'user_email', | ||||
// entitlement, wallet | // entitlement, wallet | ||||
'object_id', | 'object_id', | ||||
'object_type', | 'object_type', | ||||
Show All 15 Lines | class Transaction extends Model | ||||
]; | ]; | ||||
/** @var boolean This model uses an automatically incrementing integer primary key? */ | /** @var boolean This model uses an automatically incrementing integer primary key? */ | ||||
public $incrementing = false; | public $incrementing = false; | ||||
/** @var string The type of the primary key */ | /** @var string The type of the primary key */ | ||||
protected $keyType = 'string'; | protected $keyType = 'string'; | ||||
public const ENTITLEMENT_BILLED = 'billed'; | |||||
public const ENTITLEMENT_CREATED = 'created'; | |||||
public const ENTITLEMENT_DELETED = 'deleted'; | |||||
public const WALLET_AWARD = 'award'; | /** | ||||
public const WALLET_CREDIT = 'credit'; | * Returns the entitlement to which the transaction is assigned (if any) | ||||
public const WALLET_DEBIT = 'debit'; | * | ||||
public const WALLET_PENALTY = 'penalty'; | * @return \App\Entitlement|null The entitlement | ||||
*/ | |||||
public function entitlement() | public function entitlement(): ?Entitlement | ||||
{ | { | ||||
if ($this->object_type !== \App\Entitlement::class) { | if ($this->object_type !== Entitlement::class) { | ||||
return null; | return null; | ||||
} | } | ||||
return \App\Entitlement::withTrashed()->where('id', $this->object_id)->first(); | return Entitlement::withTrashed()->find($this->object_id); | ||||
} | } | ||||
public function setTypeAttribute($value) | /** | ||||
* Transaction type mutator | |||||
* | |||||
* @throws \Exception | |||||
*/ | |||||
public function setTypeAttribute($value): void | |||||
{ | { | ||||
switch ($value) { | switch ($value) { | ||||
case self::ENTITLEMENT_BILLED: | case self::ENTITLEMENT_BILLED: | ||||
case self::ENTITLEMENT_CREATED: | case self::ENTITLEMENT_CREATED: | ||||
case self::ENTITLEMENT_DELETED: | case self::ENTITLEMENT_DELETED: | ||||
// TODO: Must be an entitlement. | // TODO: Must be an entitlement. | ||||
$this->attributes['type'] = $value; | $this->attributes['type'] = $value; | ||||
break; | break; | ||||
case self::WALLET_AWARD: | case self::WALLET_AWARD: | ||||
case self::WALLET_CREDIT: | case self::WALLET_CREDIT: | ||||
case self::WALLET_DEBIT: | case self::WALLET_DEBIT: | ||||
case self::WALLET_PENALTY: | case self::WALLET_PENALTY: | ||||
// TODO: This must be a wallet. | // TODO: This must be a wallet. | ||||
$this->attributes['type'] = $value; | $this->attributes['type'] = $value; | ||||
break; | break; | ||||
default: | default: | ||||
throw new \Exception("Invalid type value"); | throw new \Exception("Invalid type value"); | ||||
} | } | ||||
} | } | ||||
public function toArray() | |||||
{ | |||||
$result = [ | |||||
'user_email' => $this->user_email, | |||||
'entitlement_cost' => $this->getEntitlementCost(), | |||||
'object_email' => $this->getEntitlementObjectEmail(), | |||||
'sku_title' => $this->getEntitlementSkuTitle(), | |||||
'wallet_description' => $this->getWalletDescription(), | |||||
'description' => $this->{'description'}, | |||||
'amount' => $this->amount | |||||
]; | |||||
return $result; | |||||
} | |||||
public function toString() | |||||
{ | |||||
$label = $this->objectTypeToLabelString() . '-' . $this->{'type'}; | |||||
return \trans("transactions.{$label}", $this->toArray()); | |||||
} | |||||
public function shortDescription() | |||||
{ | |||||
$label = $this->objectTypeToLabelString() . '-' . $this->{'type'} . '-short'; | |||||
return \trans("transactions.{$label}", $this->toArray()); | |||||
} | |||||
public function wallet() | |||||
{ | |||||
if ($this->object_type !== \App\Wallet::class) { | |||||
return null; | |||||
} | |||||
return \App\Wallet::where('id', $this->object_id)->first(); | |||||
} | |||||
/** | /** | ||||
* Return the costs for this entitlement. | * Returns a short text describing the transaction. | ||||
* | * | ||||
* @return int|null | * @return string The description | ||||
*/ | */ | ||||
private function getEntitlementCost(): ?int | public function shortDescription(): string | ||||
{ | { | ||||
if (!$this->entitlement()) { | $label = $this->objectTypeToLabelString() . '-' . $this->{'type'} . '-short'; | ||||
return null; | |||||
} | |||||
// FIXME: without wallet discount | |||||
// FIXME: in cents | |||||
// FIXME: without wallet currency | |||||
$cost = $this->entitlement()->cost; | |||||
$discount = $this->entitlement()->wallet->getDiscountRate(); | |||||
return $cost * $discount; | return \trans("transactions.{$label}", $this->descriptionParams()); | ||||
} | } | ||||
/** | /** | ||||
* Return the object email if any. This is the email for the target user entitlement. | * Returns a text describing the transaction. | ||||
* | * | ||||
* @return string|null | * @return string The description | ||||
*/ | */ | ||||
private function getEntitlementObjectEmail(): ?string | public function toString(): string | ||||
{ | { | ||||
$entitlement = $this->entitlement(); | $label = $this->objectTypeToLabelString() . '-' . $this->{'type'}; | ||||
if (!$entitlement) { | |||||
return null; | |||||
} | |||||
$user = \App\User::withTrashed()->where('id', $entitlement->object_id)->first(); | |||||
if (!$user) { | |||||
\Log::debug("No entitleable for {$entitlement->id} ?"); | |||||
return null; | |||||
} | |||||
return $user->email; | return \trans("transactions.{$label}", $this->descriptionParams()); | ||||
} | } | ||||
/** | /** | ||||
* Return the title for the SKU this entitlement is for. | * Returns a wallet to which the transaction is assigned (if any) | ||||
* | * | ||||
* @return string|null | * @return \App\Wallet|null The wallet | ||||
*/ | */ | ||||
private function getEntitlementSkuTitle(): ?string | public function wallet(): ?Wallet | ||||
{ | { | ||||
if (!$this->entitlement()) { | if ($this->object_type !== Wallet::class) { | ||||
return null; | return null; | ||||
} | } | ||||
return $this->entitlement()->sku->{'title'}; | return Wallet::find($this->object_id); | ||||
} | } | ||||
/** | /** | ||||
* Return the description for the wallet, if any, or 'default wallet'. | * Collect transaction parameters used in (localized) descriptions | ||||
* | * | ||||
* @return string | * @return array Parameters | ||||
*/ | */ | ||||
public function getWalletDescription() | private function descriptionParams(): array | ||||
{ | { | ||||
$description = null; | $result = [ | ||||
'user_email' => $this->user_email, | |||||
'description' => $this->{'description'}, | |||||
]; | |||||
if ($entitlement = $this->entitlement()) { | if ($entitlement = $this->entitlement()) { | ||||
$description = $entitlement->wallet->{'description'}; | $wallet = $entitlement->wallet; | ||||
$cost = $entitlement->cost; | |||||
$discount = $entitlement->wallet->getDiscountRate(); | |||||
$result['entitlement_cost'] = $cost * $discount; | |||||
$result['object'] = $entitlement->entitleableTitle(); | |||||
$result['sku_title'] = $entitlement->sku->{'title'}; | |||||
} else { | |||||
$wallet = $this->wallet(); | |||||
} | } | ||||
if ($wallet = $this->wallet()) { | $result['wallet'] = $wallet->{'description'} ?: 'Default wallet'; | ||||
$description = $wallet->{'description'}; | $result['amount'] = $wallet->money($this->amount); | ||||
} | |||||
return $description ?: 'Default wallet'; | return $result; | ||||
} | } | ||||
/** | /** | ||||
* Get a string for use in translation tables derived from the object type. | * Get a string for use in translation tables derived from the object type. | ||||
* | * | ||||
* @return string|null | * @return string|null | ||||
*/ | */ | ||||
private function objectTypeToLabelString(): ?string | private function objectTypeToLabelString(): ?string | ||||
{ | { | ||||
if ($this->object_type == \App\Entitlement::class) { | if ($this->object_type == Entitlement::class) { | ||||
return 'entitlement'; | return 'entitlement'; | ||||
} | } | ||||
if ($this->object_type == \App\Wallet::class) { | if ($this->object_type == Wallet::class) { | ||||
return 'wallet'; | return 'wallet'; | ||||
} | } | ||||
return null; | return null; | ||||
} | } | ||||
} | } |