feat(purchase): update direct item handling to support multiple items in checkout
This commit is contained in:
@@ -19,29 +19,21 @@ class StartCheckoutRequest extends FormRequest
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'cart_id' => [
|
'cart_id' => [
|
||||||
'required_without:direct_item',
|
'required_without:direct_items',
|
||||||
Rule::prohibitedIf(fn (): bool => $this->has('direct_item')),
|
Rule::prohibitedIf(fn (): bool => $this->has('direct_items')),
|
||||||
'integer',
|
'integer',
|
||||||
'exists:carritos,id',
|
'exists:carritos,id',
|
||||||
],
|
],
|
||||||
'direct_item' => [
|
'direct_items' => [
|
||||||
'required_without:cart_id',
|
'required_without:cart_id',
|
||||||
Rule::prohibitedIf(fn (): bool => $this->has('cart_id')),
|
Rule::prohibitedIf(fn (): bool => $this->has('cart_id')),
|
||||||
'array',
|
'array',
|
||||||
],
|
|
||||||
'direct_item.catalog_item_id' => [
|
|
||||||
'required_with:direct_item',
|
|
||||||
'integer',
|
|
||||||
],
|
|
||||||
'direct_item.variant_id' => [
|
|
||||||
'nullable',
|
|
||||||
'integer',
|
|
||||||
],
|
|
||||||
'direct_item.cantidad' => [
|
|
||||||
'required_with:direct_item',
|
|
||||||
'integer',
|
|
||||||
'min:1',
|
'min:1',
|
||||||
],
|
],
|
||||||
|
'direct_items.*' => ['required', 'array'],
|
||||||
|
'direct_items.*.catalog_item_id' => ['required', 'integer'],
|
||||||
|
'direct_items.*.variant_id' => ['nullable', 'integer'],
|
||||||
|
'direct_items.*.cantidad' => ['required', 'integer', 'min:1'],
|
||||||
'dni' => ['prohibited'],
|
'dni' => ['prohibited'],
|
||||||
'telefono' => ['prohibited'],
|
'telefono' => ['prohibited'],
|
||||||
'nombre_apellido' => ['prohibited'],
|
'nombre_apellido' => ['prohibited'],
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ class CatalogSelectionResolver
|
|||||||
Tenant $tenant,
|
Tenant $tenant,
|
||||||
int $catalogItemId,
|
int $catalogItemId,
|
||||||
?int $variantId,
|
?int $variantId,
|
||||||
|
string $fieldPrefix = 'direct_items',
|
||||||
): CatalogItem|Variant {
|
): CatalogItem|Variant {
|
||||||
/** @var CatalogItem|null $catalogItem */
|
/** @var CatalogItem|null $catalogItem */
|
||||||
$catalogItem = CatalogItem::query()
|
$catalogItem = CatalogItem::query()
|
||||||
@@ -31,13 +32,13 @@ class CatalogSelectionResolver
|
|||||||
if ($catalogItem->isBundle()) {
|
if ($catalogItem->isBundle()) {
|
||||||
if ($variantId !== null) {
|
if ($variantId !== null) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'direct_item.variant_id' => __('api.cart.bundle_variant_forbidden'),
|
"{$fieldPrefix}.variant_id" => __('api.cart.bundle_variant_forbidden'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $catalogItem->bundleComponents()->exists()) {
|
if (! $catalogItem->bundleComponents()->exists()) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'direct_item.catalog_item_id' => __('api.cart.empty_bundle'),
|
"{$fieldPrefix}.catalog_item_id" => __('api.cart.empty_bundle'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ class CatalogSelectionResolver
|
|||||||
if ($variantId === null) {
|
if ($variantId === null) {
|
||||||
if ($catalogItem->inventory_id === null) {
|
if ($catalogItem->inventory_id === null) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'direct_item.variant_id' => __('api.cart.variant_required'),
|
"{$fieldPrefix}.variant_id" => __('api.cart.variant_required'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,12 +33,17 @@ class StartCheckoutService
|
|||||||
->lockForUpdate()
|
->lockForUpdate()
|
||||||
->findOrFail($tenant->getKey());
|
->findOrFail($tenant->getKey());
|
||||||
|
|
||||||
$directItem = $purchaseData['direct_item'] ?? null;
|
$directItems = $purchaseData['direct_items'] ?? null;
|
||||||
$cartId = isset($purchaseData['cart_id']) ? (int) $purchaseData['cart_id'] : null;
|
$cartId = isset($purchaseData['cart_id']) ? (int) $purchaseData['cart_id'] : null;
|
||||||
unset($purchaseData['direct_item'], $purchaseData['cart_id']);
|
unset($purchaseData['direct_items'], $purchaseData['cart_id']);
|
||||||
|
|
||||||
if (is_array($directItem)) {
|
if (is_array($directItems)) {
|
||||||
return $this->startDirect($tenant, $userId, $purchaseData, $directItem);
|
return $this->startDirectItems(
|
||||||
|
$tenant,
|
||||||
|
$userId,
|
||||||
|
$purchaseData,
|
||||||
|
$directItems,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($cartId === null) {
|
if ($cartId === null) {
|
||||||
@@ -53,58 +58,110 @@ class StartCheckoutService
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array<string, mixed> $purchaseData
|
* @param array<string, mixed> $purchaseData
|
||||||
* @param array<string, mixed> $directItem
|
* @param array<int, array<string, mixed>> $directItems
|
||||||
*/
|
*/
|
||||||
private function startDirect(
|
private function startDirectItems(
|
||||||
Tenant $tenant,
|
Tenant $tenant,
|
||||||
int $userId,
|
int $userId,
|
||||||
array $purchaseData,
|
array $purchaseData,
|
||||||
array $directItem,
|
array $directItems,
|
||||||
): Purchase {
|
): Purchase {
|
||||||
$catalogItemId = (int) $directItem['catalog_item_id'];
|
$lines = collect(array_values($directItems))
|
||||||
$variantId = isset($directItem['variant_id']) ? (int) $directItem['variant_id'] : null;
|
->map(function (array $item, int $index): array {
|
||||||
$quantity = (int) $directItem['cantidad'];
|
return [
|
||||||
$selection = $this->selections->resolve($tenant, $catalogItemId, $variantId);
|
'catalog_item_id' => (int) $item['catalog_item_id'],
|
||||||
$catalogItem = $selection instanceof Variant ? $selection->catalogItem : $selection;
|
'variant_id' => isset($item['variant_id']) ? (int) $item['variant_id'] : null,
|
||||||
|
'quantity' => (int) $item['cantidad'],
|
||||||
|
'field' => "direct_items.{$index}",
|
||||||
|
];
|
||||||
|
})
|
||||||
|
->groupBy(fn (array $line): string => sprintf(
|
||||||
|
'%d:%s',
|
||||||
|
$line['catalog_item_id'],
|
||||||
|
$line['variant_id'] === null ? 'none' : (string) $line['variant_id'],
|
||||||
|
))
|
||||||
|
->map(function (Collection $duplicateLines): array {
|
||||||
|
$line = $duplicateLines->first();
|
||||||
|
$line['quantity'] = (int) $duplicateLines->sum('quantity');
|
||||||
|
|
||||||
|
return $line;
|
||||||
|
})
|
||||||
|
->sortBy(fn (array $line): string => sprintf(
|
||||||
|
'%020d:%020d',
|
||||||
|
$line['catalog_item_id'],
|
||||||
|
$line['variant_id'] ?? 0,
|
||||||
|
))
|
||||||
|
->values();
|
||||||
|
|
||||||
|
$resolvedLines = $lines->map(function (array $line) use ($tenant): array {
|
||||||
|
$selection = $this->selections->resolve(
|
||||||
|
$tenant,
|
||||||
|
$line['catalog_item_id'],
|
||||||
|
$line['variant_id'],
|
||||||
|
$line['field'],
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
...$line,
|
||||||
|
'selection' => $selection,
|
||||||
|
'catalog_item' => $selection instanceof Variant
|
||||||
|
? $selection->catalogItem
|
||||||
|
: $selection,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
$resolvedLines
|
||||||
|
->groupBy(fn (array $line): int => $line['catalog_item']->getKey())
|
||||||
|
->each(function (Collection $catalogLines) use ($userId): void {
|
||||||
|
/** @var CatalogItem $catalogItem */
|
||||||
|
$catalogItem = $catalogLines->first()['catalog_item'];
|
||||||
$this->purchaseLimits->assertCanPurchase(
|
$this->purchaseLimits->assertCanPurchase(
|
||||||
$catalogItem,
|
$catalogItem,
|
||||||
$userId,
|
$userId,
|
||||||
$quantity,
|
(int) $catalogLines->sum('quantity'),
|
||||||
field: 'direct_item.cantidad',
|
field: 'direct_items',
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
||||||
$availableQuantity = $this->inventory->availableQuantity($selection);
|
foreach ($resolvedLines as $line) {
|
||||||
|
$availableQuantity = $this->inventory->availableQuantity($line['selection']);
|
||||||
|
|
||||||
if ($availableQuantity !== null && $availableQuantity < $quantity) {
|
if ($availableQuantity !== null && $availableQuantity < $line['quantity']) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'direct_item.cantidad' => __('api.purchase.direct_item_max_stock', ['max' => $availableQuantity]),
|
"{$line['field']}.cantidad" => __('api.purchase.direct_items_max_stock', [
|
||||||
|
'max' => $availableQuantity,
|
||||||
|
]),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->inventory->reserve($selection, $quantity);
|
$this->inventory->reserve($line['selection'], $line['quantity']);
|
||||||
} catch (\InvalidArgumentException) {
|
} catch (\InvalidArgumentException) {
|
||||||
throw ValidationException::withMessages([
|
throw ValidationException::withMessages([
|
||||||
'direct_item.cantidad' => __('api.purchase.insufficient_stock'),
|
"{$line['field']}.cantidad" => __('api.purchase.insufficient_stock'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$purchase = $this->createPurchase(
|
$purchase = $this->createPurchase(
|
||||||
$tenant,
|
$tenant,
|
||||||
$userId,
|
$userId,
|
||||||
$purchaseData,
|
$purchaseData,
|
||||||
$selection->getPrice() * $quantity,
|
(float) $resolvedLines->sum(
|
||||||
|
fn (array $line): float => $line['selection']->getPrice() * $line['quantity'],
|
||||||
|
),
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
$directCartItem = $this->makeDirectCartItem(
|
|
||||||
$selection,
|
$directCartItems = $resolvedLines->map(fn (array $line): CartItem => $this->makeDirectCartItem(
|
||||||
$catalogItemId,
|
$line['selection'],
|
||||||
$variantId,
|
$line['catalog_item_id'],
|
||||||
$quantity,
|
$line['variant_id'],
|
||||||
);
|
$line['quantity'],
|
||||||
|
));
|
||||||
|
|
||||||
$purchase->items()->createMany(
|
$purchase->items()->createMany(
|
||||||
$this->snapshots->fromCartItems(collect([$directCartItem])),
|
$this->snapshots->fromCartItems($directCartItems),
|
||||||
);
|
);
|
||||||
|
|
||||||
return $this->loadPurchase($purchase);
|
return $this->loadPurchase($purchase);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ return [
|
|||||||
'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.',
|
||||||
'paid_cannot_cancel' => 'A paid purchase cannot be cancelled.',
|
'paid_cannot_cancel' => 'A paid purchase cannot be cancelled.',
|
||||||
'direct_item_max_stock' => 'There is not enough stock. Maximum available: :max.',
|
'direct_items_max_stock' => 'There is not enough stock. Maximum available: :max.',
|
||||||
'empty_cart' => 'The selected cart does not contain items.',
|
'empty_cart' => 'The selected cart does not contain items.',
|
||||||
'catalog_item_missing' => 'One or more catalog items could not be loaded.',
|
'catalog_item_missing' => 'One or more catalog items could not be loaded.',
|
||||||
'catalog_item_wrong_tenant' => 'One or more catalog items do not belong to the tenant.',
|
'catalog_item_wrong_tenant' => 'One or more catalog items do not belong to the tenant.',
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ return [
|
|||||||
'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.',
|
||||||
'paid_cannot_cancel' => 'Una compra pagada no se puede cancelar.',
|
'paid_cannot_cancel' => 'Una compra pagada no se puede cancelar.',
|
||||||
'direct_item_max_stock' => 'Stock insuficiente. Máximo disponible: :max.',
|
'direct_items_max_stock' => 'Stock insuficiente. Máximo disponible: :max.',
|
||||||
'empty_cart' => 'El carrito seleccionado no contiene productos.',
|
'empty_cart' => 'El carrito seleccionado no contiene productos.',
|
||||||
'catalog_item_missing' => 'No se pudieron cargar uno o más productos del catálogo.',
|
'catalog_item_missing' => 'No se pudieron cargar uno o más productos del catálogo.',
|
||||||
'catalog_item_wrong_tenant' => 'Uno o más productos no pertenecen al tenant.',
|
'catalog_item_wrong_tenant' => 'Uno o más productos no pertenecen al tenant.',
|
||||||
|
|||||||
@@ -143,11 +143,13 @@ class StorePurchaseTest extends TestCase
|
|||||||
|
|
||||||
$response = $this->actingAs($user, 'sanctum')
|
$response = $this->actingAs($user, 'sanctum')
|
||||||
->postJson('/api/tenants/sonder/compras/start-checkout', [
|
->postJson('/api/tenants/sonder/compras/start-checkout', [
|
||||||
'direct_item' => [
|
'direct_items' => [
|
||||||
|
[
|
||||||
'catalog_item_id' => $variant->catalog_item_id,
|
'catalog_item_id' => $variant->catalog_item_id,
|
||||||
'variant_id' => $variant->id,
|
'variant_id' => $variant->id,
|
||||||
'cantidad' => 3,
|
'cantidad' => 3,
|
||||||
],
|
],
|
||||||
|
],
|
||||||
])
|
])
|
||||||
->assertCreated()
|
->assertCreated()
|
||||||
->assertJsonPath('data.cart_id', null)
|
->assertJsonPath('data.cart_id', null)
|
||||||
@@ -185,6 +187,105 @@ class StorePurchaseTest extends TestCase
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_it_creates_one_direct_purchase_with_multiple_variant_items(): void
|
||||||
|
{
|
||||||
|
$this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
||||||
|
$user = User::factory()->create();
|
||||||
|
$firstVariant = $this->createVariantForTenant('sonder', 1, '50.00');
|
||||||
|
$secondInventory = Inventory::query()->create(['real_stock' => 1]);
|
||||||
|
$secondVariant = Variant::query()->create([
|
||||||
|
'catalog_item_id' => $firstVariant->catalog_item_id,
|
||||||
|
'inventory_id' => $secondInventory->id,
|
||||||
|
'precio' => '75.00',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = $this->actingAs($user, 'sanctum')
|
||||||
|
->postJson('/api/tenants/sonder/compras/start-checkout', [
|
||||||
|
'direct_items' => [
|
||||||
|
[
|
||||||
|
'catalog_item_id' => $firstVariant->catalog_item_id,
|
||||||
|
'variant_id' => $firstVariant->id,
|
||||||
|
'cantidad' => 1,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'catalog_item_id' => $secondVariant->catalog_item_id,
|
||||||
|
'variant_id' => $secondVariant->id,
|
||||||
|
'cantidad' => 1,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
])
|
||||||
|
->assertCreated()
|
||||||
|
->assertJsonPath('data.cart_id', null)
|
||||||
|
->assertJsonCount(2, 'data.items')
|
||||||
|
->assertJsonPath('data.items.0.source_variant_id', $firstVariant->id)
|
||||||
|
->assertJsonPath('data.items.1.source_variant_id', $secondVariant->id)
|
||||||
|
->assertJsonPath('data.total', '125.00');
|
||||||
|
|
||||||
|
$purchaseId = $response->json('data.id');
|
||||||
|
|
||||||
|
$this->assertDatabaseCount('carritos', 0);
|
||||||
|
$this->assertDatabaseHas('compra_items', [
|
||||||
|
'compra_id' => $purchaseId,
|
||||||
|
'source_variant_id' => $firstVariant->id,
|
||||||
|
'cantidad' => 1,
|
||||||
|
'reservation_status' => 'active',
|
||||||
|
]);
|
||||||
|
$this->assertDatabaseHas('compra_items', [
|
||||||
|
'compra_id' => $purchaseId,
|
||||||
|
'source_variant_id' => $secondVariant->id,
|
||||||
|
'cantidad' => 1,
|
||||||
|
'reservation_status' => 'active',
|
||||||
|
]);
|
||||||
|
$this->assertDatabaseHas('inventories', [
|
||||||
|
'id' => $firstVariant->inventory_id,
|
||||||
|
'reserved_stock' => 1,
|
||||||
|
]);
|
||||||
|
$this->assertDatabaseHas('inventories', [
|
||||||
|
'id' => $secondInventory->id,
|
||||||
|
'reserved_stock' => 1,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_multi_item_direct_purchase_rolls_back_every_reservation_when_one_item_is_unavailable(): void
|
||||||
|
{
|
||||||
|
$this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
||||||
|
$user = User::factory()->create();
|
||||||
|
$availableVariant = $this->createVariantForTenant('sonder', 1, '50.00');
|
||||||
|
$unavailableInventory = Inventory::query()->create(['real_stock' => 0]);
|
||||||
|
$unavailableVariant = Variant::query()->create([
|
||||||
|
'catalog_item_id' => $availableVariant->catalog_item_id,
|
||||||
|
'inventory_id' => $unavailableInventory->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->actingAs($user, 'sanctum')
|
||||||
|
->postJson('/api/tenants/sonder/compras/start-checkout', [
|
||||||
|
'direct_items' => [
|
||||||
|
[
|
||||||
|
'catalog_item_id' => $availableVariant->catalog_item_id,
|
||||||
|
'variant_id' => $availableVariant->id,
|
||||||
|
'cantidad' => 1,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'catalog_item_id' => $unavailableVariant->catalog_item_id,
|
||||||
|
'variant_id' => $unavailableVariant->id,
|
||||||
|
'cantidad' => 1,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
])
|
||||||
|
->assertUnprocessable()
|
||||||
|
->assertJsonValidationErrors('direct_items.1.cantidad');
|
||||||
|
|
||||||
|
$this->assertDatabaseCount('compras', 0);
|
||||||
|
$this->assertDatabaseHas('inventories', [
|
||||||
|
'id' => $availableVariant->inventory_id,
|
||||||
|
'reserved_stock' => 0,
|
||||||
|
]);
|
||||||
|
$this->assertDatabaseHas('inventories', [
|
||||||
|
'id' => $unavailableInventory->id,
|
||||||
|
'reserved_stock' => 0,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function test_it_enforces_the_user_purchase_limit_and_releases_it_after_cancellation(): void
|
public function test_it_enforces_the_user_purchase_limit_and_releases_it_after_cancellation(): void
|
||||||
{
|
{
|
||||||
$this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
$this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
||||||
@@ -195,33 +296,39 @@ class StorePurchaseTest extends TestCase
|
|||||||
|
|
||||||
$firstPurchaseId = $this->actingAs($user, 'sanctum')
|
$firstPurchaseId = $this->actingAs($user, 'sanctum')
|
||||||
->postJson('/api/tenants/sonder/compras/start-checkout', [
|
->postJson('/api/tenants/sonder/compras/start-checkout', [
|
||||||
'direct_item' => [
|
'direct_items' => [
|
||||||
|
[
|
||||||
'catalog_item_id' => $variant->catalog_item_id,
|
'catalog_item_id' => $variant->catalog_item_id,
|
||||||
'variant_id' => $variant->id,
|
'variant_id' => $variant->id,
|
||||||
'cantidad' => 2,
|
'cantidad' => 2,
|
||||||
],
|
],
|
||||||
|
],
|
||||||
])
|
])
|
||||||
->assertCreated()
|
->assertCreated()
|
||||||
->json('data.id');
|
->json('data.id');
|
||||||
|
|
||||||
$this->actingAs($user, 'sanctum')
|
$this->actingAs($user, 'sanctum')
|
||||||
->postJson('/api/tenants/sonder/compras/start-checkout', [
|
->postJson('/api/tenants/sonder/compras/start-checkout', [
|
||||||
'direct_item' => [
|
'direct_items' => [
|
||||||
|
[
|
||||||
'catalog_item_id' => $variant->catalog_item_id,
|
'catalog_item_id' => $variant->catalog_item_id,
|
||||||
'variant_id' => $variant->id,
|
'variant_id' => $variant->id,
|
||||||
'cantidad' => 2,
|
'cantidad' => 2,
|
||||||
],
|
],
|
||||||
|
],
|
||||||
])
|
])
|
||||||
->assertUnprocessable()
|
->assertUnprocessable()
|
||||||
->assertJsonValidationErrors('direct_item.cantidad');
|
->assertJsonValidationErrors('direct_items');
|
||||||
|
|
||||||
$this->actingAs($otherUser, 'sanctum')
|
$this->actingAs($otherUser, 'sanctum')
|
||||||
->postJson('/api/tenants/sonder/compras/start-checkout', [
|
->postJson('/api/tenants/sonder/compras/start-checkout', [
|
||||||
'direct_item' => [
|
'direct_items' => [
|
||||||
|
[
|
||||||
'catalog_item_id' => $variant->catalog_item_id,
|
'catalog_item_id' => $variant->catalog_item_id,
|
||||||
'variant_id' => $variant->id,
|
'variant_id' => $variant->id,
|
||||||
'cantidad' => 3,
|
'cantidad' => 3,
|
||||||
],
|
],
|
||||||
|
],
|
||||||
])
|
])
|
||||||
->assertCreated();
|
->assertCreated();
|
||||||
|
|
||||||
@@ -231,11 +338,13 @@ class StorePurchaseTest extends TestCase
|
|||||||
|
|
||||||
$this->actingAs($user, 'sanctum')
|
$this->actingAs($user, 'sanctum')
|
||||||
->postJson('/api/tenants/sonder/compras/start-checkout', [
|
->postJson('/api/tenants/sonder/compras/start-checkout', [
|
||||||
'direct_item' => [
|
'direct_items' => [
|
||||||
|
[
|
||||||
'catalog_item_id' => $variant->catalog_item_id,
|
'catalog_item_id' => $variant->catalog_item_id,
|
||||||
'variant_id' => $variant->id,
|
'variant_id' => $variant->id,
|
||||||
'cantidad' => 3,
|
'cantidad' => 3,
|
||||||
],
|
],
|
||||||
|
],
|
||||||
])
|
])
|
||||||
->assertCreated();
|
->assertCreated();
|
||||||
}
|
}
|
||||||
@@ -361,11 +470,13 @@ class StorePurchaseTest extends TestCase
|
|||||||
|
|
||||||
$purchaseResponse = $this->actingAs($user, 'sanctum')
|
$purchaseResponse = $this->actingAs($user, 'sanctum')
|
||||||
->postJson('/api/tenants/sonder/compras/start-checkout', [
|
->postJson('/api/tenants/sonder/compras/start-checkout', [
|
||||||
'direct_item' => [
|
'direct_items' => [
|
||||||
|
[
|
||||||
'catalog_item_id' => $variant->catalog_item_id,
|
'catalog_item_id' => $variant->catalog_item_id,
|
||||||
'variant_id' => $variant->id,
|
'variant_id' => $variant->id,
|
||||||
'cantidad' => 2,
|
'cantidad' => 2,
|
||||||
],
|
],
|
||||||
|
],
|
||||||
])
|
])
|
||||||
->assertCreated()
|
->assertCreated()
|
||||||
->assertJsonPath('data.items_source', 'purchase')
|
->assertJsonPath('data.items_source', 'purchase')
|
||||||
@@ -535,11 +646,13 @@ class StorePurchaseTest extends TestCase
|
|||||||
|
|
||||||
$this->actingAs($user, 'sanctum')
|
$this->actingAs($user, 'sanctum')
|
||||||
->postJson('/api/tenants/sonder/compras/start-checkout', [
|
->postJson('/api/tenants/sonder/compras/start-checkout', [
|
||||||
'direct_item' => [
|
'direct_items' => [
|
||||||
|
[
|
||||||
'catalog_item_id' => $variant->catalog_item_id,
|
'catalog_item_id' => $variant->catalog_item_id,
|
||||||
'variant_id' => $variant->id,
|
'variant_id' => $variant->id,
|
||||||
'cantidad' => 1,
|
'cantidad' => 1,
|
||||||
],
|
],
|
||||||
|
],
|
||||||
'dni' => '987654321',
|
'dni' => '987654321',
|
||||||
'telefono' => '+54 9 341 555-4321',
|
'telefono' => '+54 9 341 555-4321',
|
||||||
'nombre_apellido' => 'Juan Perez',
|
'nombre_apellido' => 'Juan Perez',
|
||||||
|
|||||||
Reference in New Issue
Block a user