refactor(checkout): remove legacy purchase item reservations
This commit is contained in:
@@ -23,18 +23,11 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|||||||
'discount_total',
|
'discount_total',
|
||||||
'tax_total',
|
'tax_total',
|
||||||
'total',
|
'total',
|
||||||
'reservation_status',
|
|
||||||
])]
|
])]
|
||||||
class PurchaseItem extends Model
|
class PurchaseItem extends Model
|
||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
|
||||||
public const RESERVATION_ACTIVE = 'active';
|
|
||||||
|
|
||||||
public const RESERVATION_COMMITTED = 'committed';
|
|
||||||
|
|
||||||
public const RESERVATION_RELEASED = 'released';
|
|
||||||
|
|
||||||
protected $table = 'compra_items';
|
protected $table = 'compra_items';
|
||||||
|
|
||||||
protected function casts(): array
|
protected function casts(): array
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ namespace App\Domains\Purchase\Services\Checkout;
|
|||||||
use App\Domains\Catalog\Models\CatalogItem;
|
use App\Domains\Catalog\Models\CatalogItem;
|
||||||
use App\Domains\Catalog\Models\Inventory;
|
use App\Domains\Catalog\Models\Inventory;
|
||||||
use App\Domains\Catalog\Models\Variant;
|
use App\Domains\Catalog\Models\Variant;
|
||||||
use App\Domains\Purchase\Models\PurchaseItem;
|
|
||||||
use App\Domains\Tenant\Models\Tenant;
|
use App\Domains\Tenant\Models\Tenant;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
@@ -79,13 +78,4 @@ class CatalogSelectionResolver
|
|||||||
|
|
||||||
return $variant;
|
return $variant;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function resolvePurchaseItem(Tenant $tenant, PurchaseItem $item): CatalogItem|Variant
|
|
||||||
{
|
|
||||||
return $this->resolve(
|
|
||||||
$tenant,
|
|
||||||
(int) $item->source_catalog_item_id,
|
|
||||||
$item->source_variant_id === null ? null : (int) $item->source_variant_id,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,8 @@
|
|||||||
namespace App\Domains\Purchase\Services\Checkout;
|
namespace App\Domains\Purchase\Services\Checkout;
|
||||||
|
|
||||||
use App\Domains\Cart\Models\CartItem;
|
use App\Domains\Cart\Models\CartItem;
|
||||||
use App\Domains\Catalog\Services\CatalogInventoryService;
|
|
||||||
use App\Domains\Catalog\Services\StockReservationService;
|
use App\Domains\Catalog\Services\StockReservationService;
|
||||||
use App\Domains\Purchase\Models\Purchase;
|
use App\Domains\Purchase\Models\Purchase;
|
||||||
use App\Domains\Purchase\Models\PurchaseItem;
|
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
@@ -14,9 +12,7 @@ use Illuminate\Validation\ValidationException;
|
|||||||
class CompleteCheckoutService
|
class CompleteCheckoutService
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly CatalogInventoryService $inventory,
|
|
||||||
private readonly StockReservationService $reservations,
|
private readonly StockReservationService $reservations,
|
||||||
private readonly CatalogSelectionResolver $selections,
|
|
||||||
private readonly SourceCartService $sourceCart,
|
private readonly SourceCartService $sourceCart,
|
||||||
private readonly PurchaseItemSnapshotFactory $snapshots,
|
private readonly PurchaseItemSnapshotFactory $snapshots,
|
||||||
) {}
|
) {}
|
||||||
@@ -89,70 +85,51 @@ class CompleteCheckoutService
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$items = $purchase->items()
|
if ($purchase->items()->exists()) {
|
||||||
->where('reservation_status', PurchaseItem::RESERVATION_ACTIVE)
|
$cart = $purchase->cart()->withTrashed()->lockForUpdate()->first();
|
||||||
->lockForUpdate()
|
if ($cart?->status === 'converted' && $cart->trashed()) {
|
||||||
->get();
|
return;
|
||||||
|
|
||||||
if ($items->isEmpty() && ! $purchase->items()->exists()) {
|
|
||||||
$cart = $purchase->cart()->lockForUpdate()->first();
|
|
||||||
if ($cart === null || $cart->status !== 'checkout') {
|
|
||||||
throw ValidationException::withMessages([
|
|
||||||
'items' => __('api.purchase.inconsistent_reservation'),
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$cartItems = $cart->items()->orderBy('id')->lockForUpdate()->get();
|
throw ValidationException::withMessages([
|
||||||
if ($cartItems->isEmpty()) {
|
'items' => __('api.purchase.inconsistent_reservation'),
|
||||||
throw ValidationException::withMessages([
|
|
||||||
'items' => __('api.purchase.inconsistent_reservation'),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->loadCartItems($cartItems);
|
|
||||||
$items = $purchase->items()->createMany(
|
|
||||||
$this->snapshots->fromCartItems($cartItems),
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($cartItems as $cartItem) {
|
|
||||||
$selection = $cartItem->selectedItem();
|
|
||||||
if ($selection === null) {
|
|
||||||
throw ValidationException::withMessages([
|
|
||||||
'items' => __('api.purchase.inconsistent_reservation'),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->reservations->commit($cartItem, $selection);
|
|
||||||
} catch (\InvalidArgumentException) {
|
|
||||||
throw ValidationException::withMessages([
|
|
||||||
'items' => __('api.purchase.inconsistent_reservation'),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$purchase->items()->update([
|
|
||||||
'reservation_status' => PurchaseItem::RESERVATION_COMMITTED,
|
|
||||||
]);
|
]);
|
||||||
$this->sourceCart->finalize($purchase);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($items as $item) {
|
$cart = $purchase->cart()->lockForUpdate()->first();
|
||||||
$selection = $this->selections->resolvePurchaseItem($purchase->tenant, $item);
|
if ($cart === null || $cart->status !== 'checkout') {
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
'items' => __('api.purchase.inconsistent_reservation'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$cartItems = $cart->items()->orderBy('id')->lockForUpdate()->get();
|
||||||
|
if ($cartItems->isEmpty()) {
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
'items' => __('api.purchase.inconsistent_reservation'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->loadCartItems($cartItems);
|
||||||
|
$purchase->items()->createMany(
|
||||||
|
$this->snapshots->fromCartItems($cartItems),
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($cartItems as $cartItem) {
|
||||||
|
$selection = $cartItem->selectedItem();
|
||||||
|
if ($selection === null) {
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
'items' => __('api.purchase.inconsistent_reservation'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->inventory->commit($selection, (int) $item->cantidad);
|
$this->reservations->commit($cartItem, $selection);
|
||||||
} catch (\InvalidArgumentException) {
|
} catch (\InvalidArgumentException) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'items' => __('api.purchase.inconsistent_reservation'),
|
'items' => __('api.purchase.inconsistent_reservation'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$item->update([
|
|
||||||
'reservation_status' => PurchaseItem::RESERVATION_COMMITTED,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->sourceCart->finalize($purchase);
|
$this->sourceCart->finalize($purchase);
|
||||||
|
|||||||
@@ -4,10 +4,8 @@ namespace App\Domains\Purchase\Services\Checkout;
|
|||||||
|
|
||||||
use App\Domains\Cart\Models\CartItem;
|
use App\Domains\Cart\Models\CartItem;
|
||||||
use App\Domains\Catalog\Models\Variant;
|
use App\Domains\Catalog\Models\Variant;
|
||||||
use App\Domains\Catalog\Services\CatalogInventoryService;
|
|
||||||
use App\Domains\Catalog\Services\StockReservationService;
|
use App\Domains\Catalog\Services\StockReservationService;
|
||||||
use App\Domains\Purchase\Models\Purchase;
|
use App\Domains\Purchase\Models\Purchase;
|
||||||
use App\Domains\Purchase\Models\PurchaseItem;
|
|
||||||
use App\Domains\Purchase\Services\UserPurchaseLimitService;
|
use App\Domains\Purchase\Services\UserPurchaseLimitService;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
@@ -16,11 +14,9 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
|||||||
class EditCheckoutService
|
class EditCheckoutService
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly CatalogInventoryService $inventory,
|
|
||||||
private readonly StockReservationService $reservations,
|
private readonly StockReservationService $reservations,
|
||||||
private readonly UserPurchaseLimitService $purchaseLimits,
|
private readonly UserPurchaseLimitService $purchaseLimits,
|
||||||
private readonly CatalogSelectionResolver $selections,
|
private readonly CatalogSelectionResolver $selections,
|
||||||
private readonly SourceCartService $sourceCart,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/** @param array<string, string> $customerData */
|
/** @param array<string, string> $customerData */
|
||||||
@@ -50,28 +46,7 @@ class EditCheckoutService
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $purchase->items()->exists()) {
|
return $this->updateCartItemQuantity($purchase, $itemId, $quantity);
|
||||||
return $this->updateCartItemQuantity($purchase, $itemId, $quantity);
|
|
||||||
}
|
|
||||||
|
|
||||||
$purchaseItem = $this->lockPurchaseItem($purchase, $itemId);
|
|
||||||
$difference = $quantity - (int) $purchaseItem->cantidad;
|
|
||||||
|
|
||||||
if ($difference !== 0) {
|
|
||||||
$this->adjustReservation($purchase, $purchaseItem, $quantity, $difference);
|
|
||||||
|
|
||||||
$purchaseItem->update([
|
|
||||||
'cantidad' => $quantity,
|
|
||||||
'total' => (float) $purchaseItem->precio_unitario * $quantity,
|
|
||||||
]);
|
|
||||||
$this->sourceCart->syncItemQuantity($purchase, $purchaseItem, $quantity);
|
|
||||||
}
|
|
||||||
|
|
||||||
$purchase->update([
|
|
||||||
'total' => $purchase->calculateCurrentTotalAmount(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
return $this->loadPurchase($purchase);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,9 +66,7 @@ class EditCheckoutService
|
|||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (! $purchase->items()->exists()) {
|
$this->attachCartReservations($purchase);
|
||||||
$this->attachCartReservations($purchase);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->loadPurchase($purchase);
|
return $this->loadPurchase($purchase);
|
||||||
});
|
});
|
||||||
@@ -151,60 +124,6 @@ class EditCheckoutService
|
|||||||
return $this->loadPurchase($purchase);
|
return $this->loadPurchase($purchase);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function adjustReservation(
|
|
||||||
Purchase $purchase,
|
|
||||||
PurchaseItem $purchaseItem,
|
|
||||||
int $quantity,
|
|
||||||
int $difference,
|
|
||||||
): void {
|
|
||||||
$selection = $this->selections->resolvePurchaseItem($purchase->tenant, $purchaseItem);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if ($difference > 0) {
|
|
||||||
$otherItemQuantity = (int) $purchase->items()
|
|
||||||
->where('source_catalog_item_id', $purchaseItem->source_catalog_item_id)
|
|
||||||
->whereKeyNot($purchaseItem->getKey())
|
|
||||||
->sum('cantidad');
|
|
||||||
$catalogItem = $selection instanceof Variant ? $selection->catalogItem : $selection;
|
|
||||||
|
|
||||||
$this->purchaseLimits->assertCanPurchase(
|
|
||||||
$catalogItem,
|
|
||||||
(int) $purchase->user_id,
|
|
||||||
$otherItemQuantity + $quantity,
|
|
||||||
$purchase->getKey(),
|
|
||||||
);
|
|
||||||
$this->inventory->reserve($selection, $difference);
|
|
||||||
} else {
|
|
||||||
$this->inventory->release($selection, abs($difference));
|
|
||||||
}
|
|
||||||
} catch (\InvalidArgumentException) {
|
|
||||||
throw ValidationException::withMessages([
|
|
||||||
'quantity' => __('api.purchase.insufficient_stock'),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function lockPurchaseItem(Purchase $purchase, int $itemId): PurchaseItem
|
|
||||||
{
|
|
||||||
/** @var PurchaseItem|null $lockedItem */
|
|
||||||
$lockedItem = $purchase->items()
|
|
||||||
->whereKey($itemId)
|
|
||||||
->lockForUpdate()
|
|
||||||
->first();
|
|
||||||
|
|
||||||
if ($lockedItem === null) {
|
|
||||||
throw new NotFoundHttpException('Purchase item not found.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($lockedItem->reservation_status !== PurchaseItem::RESERVATION_ACTIVE) {
|
|
||||||
throw ValidationException::withMessages([
|
|
||||||
'item' => __('api.purchase.item_not_editable'),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $lockedItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function attachCartReservations(Purchase $purchase): void
|
private function attachCartReservations(Purchase $purchase): void
|
||||||
{
|
{
|
||||||
$cartItems = $purchase->cart?->items()->lockForUpdate()->get() ?? collect();
|
$cartItems = $purchase->cart?->items()->lockForUpdate()->get() ?? collect();
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ namespace App\Domains\Purchase\Services\Checkout;
|
|||||||
use App\Domains\Attachable\Models\Attachment;
|
use App\Domains\Attachable\Models\Attachment;
|
||||||
use App\Domains\Cart\Models\CartItem;
|
use App\Domains\Cart\Models\CartItem;
|
||||||
use App\Domains\Catalog\Models\Variant;
|
use App\Domains\Catalog\Models\Variant;
|
||||||
use App\Domains\Purchase\Models\PurchaseItem;
|
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
class PurchaseItemSnapshotFactory
|
class PurchaseItemSnapshotFactory
|
||||||
@@ -38,7 +37,6 @@ class PurchaseItemSnapshotFactory
|
|||||||
'discount_total' => null,
|
'discount_total' => null,
|
||||||
'tax_total' => null,
|
'tax_total' => null,
|
||||||
'total' => $unitPrice * $quantity,
|
'total' => $unitPrice * $quantity,
|
||||||
'reservation_status' => PurchaseItem::RESERVATION_ACTIVE,
|
|
||||||
];
|
];
|
||||||
})
|
})
|
||||||
->all();
|
->all();
|
||||||
|
|||||||
@@ -3,19 +3,15 @@
|
|||||||
namespace App\Domains\Purchase\Services\Checkout;
|
namespace App\Domains\Purchase\Services\Checkout;
|
||||||
|
|
||||||
use App\Domains\Catalog\Models\StockReservation;
|
use App\Domains\Catalog\Models\StockReservation;
|
||||||
use App\Domains\Catalog\Services\CatalogInventoryService;
|
|
||||||
use App\Domains\Catalog\Services\StockReservationService;
|
use App\Domains\Catalog\Services\StockReservationService;
|
||||||
use App\Domains\Purchase\Models\Purchase;
|
use App\Domains\Purchase\Models\Purchase;
|
||||||
use App\Domains\Purchase\Models\PurchaseItem;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
class ReleaseCheckoutService
|
class ReleaseCheckoutService
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly CatalogInventoryService $inventory,
|
|
||||||
private readonly StockReservationService $reservations,
|
private readonly StockReservationService $reservations,
|
||||||
private readonly CatalogSelectionResolver $selections,
|
|
||||||
private readonly SourceCartService $sourceCart,
|
private readonly SourceCartService $sourceCart,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -80,29 +76,15 @@ class ReleaseCheckoutService
|
|||||||
return $this->loadPurchase($purchase);
|
return $this->loadPurchase($purchase);
|
||||||
}
|
}
|
||||||
|
|
||||||
$items = $purchase->items()
|
if ($purchase->items()->exists()) {
|
||||||
->where('reservation_status', PurchaseItem::RESERVATION_ACTIVE)
|
throw ValidationException::withMessages([
|
||||||
->lockForUpdate()
|
'items' => __('api.purchase.inconsistent_reservation'),
|
||||||
->get();
|
|
||||||
$reservationReturnedToCart = $restoreCart && $this->sourceCart->restore($purchase);
|
|
||||||
|
|
||||||
if ($items->isEmpty() && ! $purchase->items()->exists()) {
|
|
||||||
$this->releaseCartReservations($purchase, $reservationReturnedToCart, $targetStatus);
|
|
||||||
$purchase->update(['status' => $targetStatus]);
|
|
||||||
|
|
||||||
return $this->loadPurchase($purchase);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($items as $item) {
|
|
||||||
if (! $reservationReturnedToCart) {
|
|
||||||
$this->releaseInventory($purchase, $item);
|
|
||||||
}
|
|
||||||
|
|
||||||
$item->update([
|
|
||||||
'reservation_status' => PurchaseItem::RESERVATION_RELEASED,
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$reservationReturnedToCart = $restoreCart && $this->sourceCart->restore($purchase);
|
||||||
|
$this->releaseCartReservations($purchase, $reservationReturnedToCart, $targetStatus);
|
||||||
|
|
||||||
$purchase->update(['status' => $targetStatus]);
|
$purchase->update(['status' => $targetStatus]);
|
||||||
|
|
||||||
return $this->loadPurchase($purchase);
|
return $this->loadPurchase($purchase);
|
||||||
@@ -162,19 +144,6 @@ class ReleaseCheckoutService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function releaseInventory(Purchase $purchase, PurchaseItem $item): void
|
|
||||||
{
|
|
||||||
$selection = $this->selections->resolvePurchaseItem($purchase->tenant, $item);
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->inventory->release($selection, (int) $item->cantidad);
|
|
||||||
} catch (\InvalidArgumentException) {
|
|
||||||
throw ValidationException::withMessages([
|
|
||||||
'items' => __('api.purchase.inconsistent_reservation'),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function isAlreadyReleased(Purchase $purchase): bool
|
private function isAlreadyReleased(Purchase $purchase): bool
|
||||||
{
|
{
|
||||||
return in_array($purchase->status, [
|
return in_array($purchase->status, [
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use App\Domains\Cart\Models\Cart;
|
|||||||
use App\Domains\Cart\Models\CartItem;
|
use App\Domains\Cart\Models\CartItem;
|
||||||
use App\Domains\Catalog\Services\StockReservationService;
|
use App\Domains\Catalog\Services\StockReservationService;
|
||||||
use App\Domains\Purchase\Models\Purchase;
|
use App\Domains\Purchase\Models\Purchase;
|
||||||
use App\Domains\Purchase\Models\PurchaseItem;
|
|
||||||
|
|
||||||
class SourceCartService
|
class SourceCartService
|
||||||
{
|
{
|
||||||
@@ -63,23 +62,6 @@ class SourceCartService
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function syncItemQuantity(
|
|
||||||
Purchase $purchase,
|
|
||||||
PurchaseItem $purchaseItem,
|
|
||||||
int $quantity,
|
|
||||||
): void {
|
|
||||||
$sourceCart = $this->findSourceCart($purchase);
|
|
||||||
|
|
||||||
if ($sourceCart === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sourceCart->items()
|
|
||||||
->where('catalog_item_id', $purchaseItem->source_catalog_item_id)
|
|
||||||
->where('variant_id', $purchaseItem->source_variant_id)
|
|
||||||
->update(['cantidad' => $quantity]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function finalize(Purchase $purchase): void
|
public function finalize(Purchase $purchase): void
|
||||||
{
|
{
|
||||||
$sourceCart = $this->findSourceCart($purchase);
|
$sourceCart = $this->findSourceCart($purchase);
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('compra_items', function (Blueprint $table): void {
|
||||||
|
$table->dropColumn('reservation_status');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('compra_items', function (Blueprint $table): void {
|
||||||
|
$table->string('reservation_status')
|
||||||
|
->default('committed')
|
||||||
|
->after('total');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -37,7 +37,6 @@ return [
|
|||||||
'source_required' => 'A cart or direct item is required.',
|
'source_required' => 'A cart or direct item is required.',
|
||||||
'payment_method_required' => 'The purchase payment method must be selected before finalizing.',
|
'payment_method_required' => 'The purchase payment method must be selected before finalizing.',
|
||||||
'not_editable' => 'The purchase is no longer editable.',
|
'not_editable' => 'The purchase is no longer editable.',
|
||||||
'item_not_editable' => 'The purchase item is no longer editable.',
|
|
||||||
'insufficient_stock' => 'There is not enough stock available.',
|
'insufficient_stock' => 'There is not enough stock available.',
|
||||||
'cannot_confirm' => 'A cancelled, rejected, or expired purchase cannot be confirmed.',
|
'cannot_confirm' => 'A cancelled, rejected, or expired purchase cannot be confirmed.',
|
||||||
'inconsistent_reservation' => 'The purchase has an inconsistent stock reservation.',
|
'inconsistent_reservation' => 'The purchase has an inconsistent stock reservation.',
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ return [
|
|||||||
'source_required' => 'Se requiere un carrito o un producto directo.',
|
'source_required' => 'Se requiere un carrito o un producto directo.',
|
||||||
'payment_method_required' => 'Debes seleccionar el método de pago antes de finalizar la compra.',
|
'payment_method_required' => 'Debes seleccionar el método de pago antes de finalizar la compra.',
|
||||||
'not_editable' => 'La compra ya no se puede modificar.',
|
'not_editable' => 'La compra ya no se puede modificar.',
|
||||||
'item_not_editable' => 'El producto de la compra ya no se puede modificar.',
|
|
||||||
'insufficient_stock' => 'No hay suficiente stock disponible.',
|
'insufficient_stock' => 'No hay suficiente stock disponible.',
|
||||||
'cannot_confirm' => 'Una compra cancelada, rechazada o vencida no se puede confirmar.',
|
'cannot_confirm' => 'Una compra cancelada, rechazada o vencida no se puede confirmar.',
|
||||||
'inconsistent_reservation' => 'La compra tiene una reserva de stock inconsistente.',
|
'inconsistent_reservation' => 'La compra tiene una reserva de stock inconsistente.',
|
||||||
|
|||||||
@@ -523,7 +523,6 @@ class CartControllerTest extends TestCase
|
|||||||
'cantidad' => $quantity,
|
'cantidad' => $quantity,
|
||||||
'precio_unitario' => $item->precio,
|
'precio_unitario' => $item->precio,
|
||||||
'total' => (float) $item->precio * $quantity,
|
'total' => (float) $item->precio * $quantity,
|
||||||
'reservation_status' => PurchaseItem::RESERVATION_COMMITTED,
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ class PurchaseCatalogItemTest extends TestCase
|
|||||||
$this->assertFalse(Schema::hasColumn('compra_items', 'variant_id'));
|
$this->assertFalse(Schema::hasColumn('compra_items', 'variant_id'));
|
||||||
$this->assertFalse(Schema::hasColumn('compra_items', 'buyable_type'));
|
$this->assertFalse(Schema::hasColumn('compra_items', 'buyable_type'));
|
||||||
$this->assertFalse(Schema::hasColumn('compra_items', 'buyable_id'));
|
$this->assertFalse(Schema::hasColumn('compra_items', 'buyable_id'));
|
||||||
|
$this->assertFalse(Schema::hasColumn('compra_items', 'reservation_status'));
|
||||||
$this->assertDatabaseHas('compra_items', [
|
$this->assertDatabaseHas('compra_items', [
|
||||||
'compra_id' => $purchase->id,
|
'compra_id' => $purchase->id,
|
||||||
'source_catalog_item_id' => $catalogItem->id,
|
'source_catalog_item_id' => $catalogItem->id,
|
||||||
|
|||||||
@@ -559,7 +559,7 @@ class StorePurchaseTest extends TestCase
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_it_updates_a_created_purchase_item_quantity_and_its_stock_reservation(): void
|
public function test_it_updates_a_checkout_cart_item_quantity_and_its_stock_reservation(): void
|
||||||
{
|
{
|
||||||
$this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
$this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
|
|||||||
Reference in New Issue
Block a user