refactor(backend): reorganize domains into Core, Commerce, Ticketing and Shared
This commit is contained in:
279
app/Domains/Commerce/Purchase/Models/Purchase.php
Normal file
279
app/Domains/Commerce/Purchase/Models/Purchase.php
Normal file
@@ -0,0 +1,279 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Purchase\Models;
|
||||
|
||||
use App\Domains\Auth\Models\User;
|
||||
use App\Domains\Cart\Models\Cart;
|
||||
use App\Domains\Catalog\Models\StockReservation;
|
||||
use App\Domains\Logging\Models\Concerns\LogsValueChanges;
|
||||
use App\Domains\Purchase\Events\PurchasePaid;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use App\Domains\Ticket\Models\Ticket;
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
#[Fillable([
|
||||
'cart_id',
|
||||
'stock_reservation_id',
|
||||
'tenant_codigo',
|
||||
'user_id',
|
||||
'status',
|
||||
'payment_method',
|
||||
'total',
|
||||
'dni',
|
||||
'transfer_payer_dni',
|
||||
'telefono',
|
||||
'nombre_apellido',
|
||||
'email',
|
||||
])]
|
||||
class Purchase extends Model
|
||||
{
|
||||
use HasFactory, LogsValueChanges;
|
||||
|
||||
public const STATUS_CREATED = 'created';
|
||||
|
||||
public const STATUS_PENDING_PAYMENT = 'pending_payment';
|
||||
|
||||
public const STATUS_IN_REVIEW = 'in_review';
|
||||
|
||||
public const STATUS_PAID = 'paid';
|
||||
|
||||
public const STATUS_CANCELLED = 'cancelled';
|
||||
|
||||
public const STATUS_REJECTED = 'rejected';
|
||||
|
||||
public const STATUS_EXPIRED = 'expired';
|
||||
|
||||
public const STATUS_SUPERSEDED = 'superseded';
|
||||
|
||||
public const ADMIN_STATUS_INCOMPLETE = 'incomplete';
|
||||
|
||||
public const ADMIN_STATUS_AWAITING_PAYMENT = 'awaiting_payment';
|
||||
|
||||
public const ADMIN_STATUS_CONFIRMED = 'confirmed';
|
||||
|
||||
public const ADMIN_STATUS_CANCELLED = 'cancelled';
|
||||
|
||||
/** @return list<string> */
|
||||
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<string, array{name: string, statuses: list<string>}>
|
||||
*/
|
||||
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<string> */
|
||||
public static function adminStatusCodes(): array
|
||||
{
|
||||
return array_keys(self::adminStatuses());
|
||||
}
|
||||
|
||||
/** @return list<string> */
|
||||
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<int, string> */
|
||||
protected array $loggedAttributes = [
|
||||
'status',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'cart_id' => 'integer',
|
||||
'stock_reservation_id' => 'integer',
|
||||
'user_id' => 'integer',
|
||||
'total' => 'decimal:2',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Tenant, $this>
|
||||
*/
|
||||
public function tenant(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Tenant::class, 'tenant_codigo', 'codigo');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo<User, $this>
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Cart, $this>
|
||||
*/
|
||||
public function cart(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Cart::class, 'cart_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HasMany<PurchaseItem, $this>
|
||||
*/
|
||||
public function items(): HasMany
|
||||
{
|
||||
return $this->hasMany(PurchaseItem::class, 'compra_id');
|
||||
}
|
||||
|
||||
/** @return HasManyThrough<Ticket, PurchaseItem, $this> */
|
||||
public function tickets(): HasManyThrough
|
||||
{
|
||||
return $this->hasManyThrough(
|
||||
Ticket::class,
|
||||
PurchaseItem::class,
|
||||
'compra_id',
|
||||
'source_purchase_item_id',
|
||||
);
|
||||
}
|
||||
|
||||
/** @return BelongsTo<StockReservation, $this> */
|
||||
public function stockReservation(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(StockReservation::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HasOne<TelepagosQr, $this>
|
||||
*/
|
||||
public function telepagosQr()
|
||||
{
|
||||
return $this->hasOne(TelepagosQr::class, 'compra_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HasMany<TelepagosPayment, $this>
|
||||
*/
|
||||
public function telepagosPayments(): HasMany
|
||||
{
|
||||
return $this->hasMany(TelepagosPayment::class, 'compra_id');
|
||||
}
|
||||
|
||||
/** @return HasMany<TelepagosPaymentCandidate, $this> */
|
||||
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());
|
||||
});
|
||||
}
|
||||
}
|
||||
91
app/Domains/Commerce/Purchase/Models/PurchaseItem.php
Normal file
91
app/Domains/Commerce/Purchase/Models/PurchaseItem.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Purchase\Models;
|
||||
|
||||
use App\Domains\Attachable\Models\Attachment;
|
||||
use App\Domains\Catalog\Models\CatalogItem;
|
||||
use App\Domains\Catalog\Models\Variant;
|
||||
use App\Domains\Ticket\Models\Ticket;
|
||||
use App\Domains\Ticket\Models\TicketRefund;
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
#[Fillable([
|
||||
'compra_id',
|
||||
'source_catalog_item_id',
|
||||
'source_variant_id',
|
||||
'image_attachment_id',
|
||||
'nombre',
|
||||
'descripcion',
|
||||
'slug',
|
||||
'item_nombre',
|
||||
'variant_attributes',
|
||||
'cantidad',
|
||||
'precio_unitario',
|
||||
'discount_total',
|
||||
'tax_total',
|
||||
'total',
|
||||
])]
|
||||
class PurchaseItem extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'compra_items';
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'compra_id' => 'integer',
|
||||
'source_catalog_item_id' => 'integer',
|
||||
'source_variant_id' => 'integer',
|
||||
'image_attachment_id' => 'integer',
|
||||
'variant_attributes' => 'array',
|
||||
'cantidad' => 'integer',
|
||||
'precio_unitario' => 'decimal:2',
|
||||
'discount_total' => 'decimal:2',
|
||||
'tax_total' => 'decimal:2',
|
||||
'total' => 'decimal:2',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Purchase, $this>
|
||||
*/
|
||||
public function purchase(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Purchase::class, 'compra_id');
|
||||
}
|
||||
|
||||
/** @return HasMany<Ticket, $this> */
|
||||
public function tickets(): HasMany
|
||||
{
|
||||
return $this->hasMany(Ticket::class, 'source_purchase_item_id');
|
||||
}
|
||||
|
||||
/** @return HasMany<TicketRefund, $this> */
|
||||
public function ticketRefunds(): HasMany
|
||||
{
|
||||
return $this->hasMany(TicketRefund::class);
|
||||
}
|
||||
|
||||
/** @return BelongsTo<Attachment, $this> */
|
||||
public function imageAttachment(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Attachment::class, 'image_attachment_id');
|
||||
}
|
||||
|
||||
/** @return BelongsTo<CatalogItem, $this> */
|
||||
public function sourceCatalogItem(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(CatalogItem::class, 'source_catalog_item_id')->withTrashed();
|
||||
}
|
||||
|
||||
/** @return BelongsTo<Variant, $this> */
|
||||
public function sourceVariant(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Variant::class, 'source_variant_id')->withTrashed();
|
||||
}
|
||||
}
|
||||
50
app/Domains/Commerce/Purchase/Models/TelepagosPayment.php
Normal file
50
app/Domains/Commerce/Purchase/Models/TelepagosPayment.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Purchase\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
#[Fillable([
|
||||
'compra_id',
|
||||
'cuit_buyer',
|
||||
'cvu_buyer',
|
||||
'amount',
|
||||
'concept',
|
||||
'operation',
|
||||
'operation_id',
|
||||
'transaction_id',
|
||||
'qr_order_id',
|
||||
'link_id',
|
||||
])]
|
||||
class TelepagosPayment extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'telepagos_payments';
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'compra_id' => 'integer',
|
||||
'amount' => 'decimal:2',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Purchase, $this>
|
||||
*/
|
||||
public function compra(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Purchase::class, 'compra_id');
|
||||
}
|
||||
|
||||
/** @return HasMany<TelepagosPaymentCandidate, $this> */
|
||||
public function candidates(): HasMany
|
||||
{
|
||||
return $this->hasMany(TelepagosPaymentCandidate::class, 'telepagos_payment_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Purchase\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
#[Fillable([
|
||||
'telepagos_payment_id',
|
||||
'compra_id',
|
||||
'dni_matches',
|
||||
'dni_distance',
|
||||
'payment_dni',
|
||||
'purchase_dni',
|
||||
'amount_matches',
|
||||
'payment_amount',
|
||||
'purchase_amount',
|
||||
'amount_difference',
|
||||
'match_reason',
|
||||
'confidence',
|
||||
])]
|
||||
class TelepagosPaymentCandidate extends Model
|
||||
{
|
||||
protected $table = 'telepagos_payment_candidates';
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'telepagos_payment_id' => 'integer',
|
||||
'compra_id' => 'integer',
|
||||
'dni_matches' => 'boolean',
|
||||
'dni_distance' => 'integer',
|
||||
'amount_matches' => 'boolean',
|
||||
'payment_amount' => 'decimal:2',
|
||||
'purchase_amount' => 'decimal:2',
|
||||
'amount_difference' => 'decimal:2',
|
||||
];
|
||||
}
|
||||
|
||||
public function payment(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(TelepagosPayment::class, 'telepagos_payment_id');
|
||||
}
|
||||
|
||||
public function purchase(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Purchase::class, 'compra_id');
|
||||
}
|
||||
}
|
||||
35
app/Domains/Commerce/Purchase/Models/TelepagosQr.php
Normal file
35
app/Domains/Commerce/Purchase/Models/TelepagosQr.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Purchase\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
#[Fillable([
|
||||
'compra_id',
|
||||
'qr_order_id',
|
||||
'qr_code',
|
||||
])]
|
||||
class TelepagosQr extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'telepagos_qr';
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'compra_id' => 'integer',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Purchase, $this>
|
||||
*/
|
||||
public function compra(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Purchase::class, 'compra_id');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user