*/ public static function statuses(): array { return [ self::STATUS_CREATED, self::STATUS_PENDING_PAYMENT, self::STATUS_IN_REVIEW, self::STATUS_PAID, self::STATUS_CANCELLED, self::STATUS_REJECTED, self::STATUS_EXPIRED, self::STATUS_SUPERSEDED, ]; } /** * @return array}> */ public static function adminStatuses(): array { return [ self::ADMIN_STATUS_INCOMPLETE => [ 'name' => 'Por completar datos', 'statuses' => [self::STATUS_CREATED], ], self::ADMIN_STATUS_AWAITING_PAYMENT => [ 'name' => 'Esperando pago', 'statuses' => [self::STATUS_PENDING_PAYMENT, self::STATUS_IN_REVIEW], ], self::ADMIN_STATUS_CONFIRMED => [ 'name' => 'Confirmado', 'statuses' => [self::STATUS_PAID], ], self::ADMIN_STATUS_CANCELLED => [ 'name' => 'Anulado', 'statuses' => [ self::STATUS_CANCELLED, self::STATUS_REJECTED, self::STATUS_EXPIRED, self::STATUS_SUPERSEDED, ], ], ]; } /** @return list */ public static function adminStatusCodes(): array { return array_keys(self::adminStatuses()); } /** @return list */ public static function realStatusesForAdminStatus(string $adminStatus): array { return self::adminStatuses()[$adminStatus]['statuses'] ?? []; } public static function adminStatusFor(string $realStatus): ?string { foreach (self::adminStatuses() as $adminStatus => $definition) { if (in_array($realStatus, $definition['statuses'], true)) { return $adminStatus; } } return null; } public static function adminStatusNameFor(string $realStatus): ?string { $adminStatus = self::adminStatusFor($realStatus); return $adminStatus === null ? null : self::adminStatuses()[$adminStatus]['name']; } protected $table = 'compras'; /** @var array */ protected array $loggedAttributes = [ 'status', ]; protected function casts(): array { return [ 'cart_id' => 'integer', 'stock_reservation_id' => 'integer', 'user_id' => 'integer', 'total' => 'decimal:2', ]; } /** * @return BelongsTo */ public function tenant(): BelongsTo { return $this->belongsTo(Tenant::class, 'tenant_codigo', 'codigo'); } /** * @return BelongsTo */ public function user(): BelongsTo { return $this->belongsTo(User::class); } /** * @return BelongsTo */ public function cart(): BelongsTo { return $this->belongsTo(Cart::class, 'cart_id'); } /** * @return HasMany */ public function items(): HasMany { return $this->hasMany(PurchaseItem::class, 'compra_id'); } /** @return HasManyThrough */ public function tickets(): HasManyThrough { return $this->hasManyThrough( Ticket::class, PurchaseItem::class, 'compra_id', 'source_purchase_item_id', ); } /** @return BelongsTo */ public function stockReservation(): BelongsTo { return $this->belongsTo(StockReservation::class); } /** * @return HasOne */ public function telepagosQr() { return $this->hasOne(TelepagosQr::class, 'compra_id'); } /** * @return HasMany */ public function telepagosPayments(): HasMany { return $this->hasMany(TelepagosPayment::class, 'compra_id'); } /** @return HasMany */ public function telepagosPaymentCandidates(): HasMany { return $this->hasMany(TelepagosPaymentCandidate::class, 'compra_id'); } public function getTotalAmount(): float { if ($this->total !== null) { return (float) $this->total; } return $this->calculateCurrentTotalAmount(); } public function calculateCurrentTotalAmount(): float { if ($this->relationLoaded('items') && $this->getRelation('items')->isNotEmpty()) { return (float) $this->getRelation('items')->sum('total'); } return (float) $this->items()->sum('total'); } protected function valueChangeTenantCode(): string { return $this->tenant_codigo; } public function markAsPendingPayment(): void { $this->update([ 'status' => self::STATUS_PENDING_PAYMENT, ]); } public function markAsPaid(): void { DB::transaction(function (): void { $currentStatus = self::query() ->whereKey($this->getKey()) ->lockForUpdate() ->value('status'); if ($currentStatus === self::STATUS_PAID) { $this->status = self::STATUS_PAID; return; } $this->update([ 'status' => self::STATUS_PAID, ]); PurchasePaid::dispatch($this->getKey()); }); } }