Compare commits
5 Commits
feature/va
...
615eacea91
| Author | SHA1 | Date | |
|---|---|---|---|
| 615eacea91 | |||
| 84c9fa4c9d | |||
| b3d06431e5 | |||
| 379c2bdbeb | |||
| ca7a2ae55c |
@@ -12,9 +12,9 @@ class CatalogController extends Controller
|
|||||||
public function index(string $tenant): JsonResponse
|
public function index(string $tenant): JsonResponse
|
||||||
{
|
{
|
||||||
$featuredGroups = FeaturedGroup::where('tenant_codigo', $tenant)
|
$featuredGroups = FeaturedGroup::where('tenant_codigo', $tenant)
|
||||||
->with(['featuredVariants' => function ($query) {
|
->with(['groupItems' => function ($query) {
|
||||||
$query->orderBy('order');
|
$query->orderBy('order');
|
||||||
}, 'featuredVariants.variant.product', 'featuredVariants.variant.attachments', 'featuredVariants.variant.product.attachments'])
|
}, 'groupItems.variant.product', 'groupItems.variant.attachments', 'groupItems.variant.product.attachments'])
|
||||||
->orderBy('group_order')
|
->orderBy('group_order')
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class FeaturedGroupController extends Controller
|
|||||||
public function show(string $tenant, FeaturedGroup $featuredGroup): FeaturedGroupResource
|
public function show(string $tenant, FeaturedGroup $featuredGroup): FeaturedGroupResource
|
||||||
{
|
{
|
||||||
abort_if($featuredGroup->tenant_codigo !== $tenant, 404);
|
abort_if($featuredGroup->tenant_codigo !== $tenant, 404);
|
||||||
return new FeaturedGroupResource($featuredGroup->load('featuredVariants'));
|
return new FeaturedGroupResource($featuredGroup->load('groupItems'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(UpdateFeaturedGroupRequest $request, string $tenant, FeaturedGroup $featuredGroup): FeaturedGroupResource
|
public function update(UpdateFeaturedGroupRequest $request, string $tenant, FeaturedGroup $featuredGroup): FeaturedGroupResource
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
namespace App\Domains\Catalog\Controllers;
|
namespace App\Domains\Catalog\Controllers;
|
||||||
|
|
||||||
use App\Domains\Catalog\Models\FeaturedGroup;
|
use App\Domains\Catalog\Models\FeaturedGroup;
|
||||||
use App\Domains\Catalog\Models\FeaturedVariant;
|
use App\Domains\Catalog\Models\GroupItem;
|
||||||
use App\Domains\Catalog\Requests\StoreFeaturedVariantRequest;
|
use App\Domains\Catalog\Requests\StoreFeaturedVariantRequest;
|
||||||
use App\Domains\Catalog\Requests\UpdateFeaturedVariantRequest;
|
use App\Domains\Catalog\Requests\UpdateFeaturedVariantRequest;
|
||||||
use App\Domains\Catalog\Resources\FeaturedVariantResource;
|
use App\Domains\Catalog\Resources\FeaturedVariantResource;
|
||||||
@@ -16,24 +16,24 @@ class FeaturedVariantController extends Controller
|
|||||||
public function index(string $tenant, FeaturedGroup $featuredGroup): AnonymousResourceCollection
|
public function index(string $tenant, FeaturedGroup $featuredGroup): AnonymousResourceCollection
|
||||||
{
|
{
|
||||||
abort_if($featuredGroup->tenant_codigo !== $tenant, 404);
|
abort_if($featuredGroup->tenant_codigo !== $tenant, 404);
|
||||||
return FeaturedVariantResource::collection($featuredGroup->featuredVariants);
|
return FeaturedVariantResource::collection($featuredGroup->groupItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function store(StoreFeaturedVariantRequest $request, string $tenant, FeaturedGroup $featuredGroup): FeaturedVariantResource
|
public function store(StoreFeaturedVariantRequest $request, string $tenant, FeaturedGroup $featuredGroup): FeaturedVariantResource
|
||||||
{
|
{
|
||||||
abort_if($featuredGroup->tenant_codigo !== $tenant, 404);
|
abort_if($featuredGroup->tenant_codigo !== $tenant, 404);
|
||||||
$variant = $featuredGroup->featuredVariants()->create($request->validated());
|
$variant = $featuredGroup->groupItems()->create($request->validated());
|
||||||
return new FeaturedVariantResource($variant);
|
return new FeaturedVariantResource($variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(UpdateFeaturedVariantRequest $request, string $tenant, FeaturedGroup $featuredGroup, FeaturedVariant $featuredVariant): FeaturedVariantResource
|
public function update(UpdateFeaturedVariantRequest $request, string $tenant, FeaturedGroup $featuredGroup, GroupItem $featuredVariant): FeaturedVariantResource
|
||||||
{
|
{
|
||||||
abort_if($featuredGroup->tenant_codigo !== $tenant || $featuredVariant->featured_group_id !== $featuredGroup->id, 404);
|
abort_if($featuredGroup->tenant_codigo !== $tenant || $featuredVariant->featured_group_id !== $featuredGroup->id, 404);
|
||||||
$featuredVariant->update($request->validated());
|
$featuredVariant->update($request->validated());
|
||||||
return new FeaturedVariantResource($featuredVariant);
|
return new FeaturedVariantResource($featuredVariant);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function destroy(string $tenant, FeaturedGroup $featuredGroup, FeaturedVariant $featuredVariant): JsonResponse
|
public function destroy(string $tenant, FeaturedGroup $featuredGroup, GroupItem $featuredVariant): JsonResponse
|
||||||
{
|
{
|
||||||
abort_if($featuredGroup->tenant_codigo !== $tenant || $featuredVariant->featured_group_id !== $featuredGroup->id, 404);
|
abort_if($featuredGroup->tenant_codigo !== $tenant || $featuredVariant->featured_group_id !== $featuredGroup->id, 404);
|
||||||
$featuredVariant->delete();
|
$featuredVariant->delete();
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ class FeaturedGroup extends Model
|
|||||||
'group_order',
|
'group_order',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function featuredVariants(): HasMany
|
public function groupItems(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(FeaturedVariant::class);
|
return $this->hasMany(GroupItem::class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,12 @@
|
|||||||
|
|
||||||
namespace App\Domains\Catalog\Models;
|
namespace App\Domains\Catalog\Models;
|
||||||
|
|
||||||
use App\Domains\Catalog\Models\ProductVariant;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
|
||||||
class FeaturedVariant extends Model
|
class GroupItem extends Model
|
||||||
{
|
{
|
||||||
protected $table = 'featured_variants';
|
protected $table = 'group_items';
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'featured_group_id',
|
'featured_group_id',
|
||||||
@@ -4,7 +4,7 @@ namespace App\Domains\Catalog\Resources;
|
|||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
use App\Domains\Catalog\Models\FeaturedVariant;
|
use App\Domains\Catalog\Models\GroupItem;
|
||||||
|
|
||||||
class CatalogFeaturedGroupResource extends JsonResource
|
class CatalogFeaturedGroupResource extends JsonResource
|
||||||
{
|
{
|
||||||
@@ -15,9 +15,9 @@ class CatalogFeaturedGroupResource extends JsonResource
|
|||||||
'title' => $this->group_name,
|
'title' => $this->group_name,
|
||||||
'layout' => $this->product_layout,
|
'layout' => $this->product_layout,
|
||||||
'group_order' => $this->group_order,
|
'group_order' => $this->group_order,
|
||||||
'items' => $this->whenLoaded('featuredVariants', function () use ($request) {
|
'items' => $this->whenLoaded('groupItems', function () use ($request) {
|
||||||
return $this->featuredVariants->map(function (FeaturedVariant $featuredVariant) use ($request) {
|
return $this->groupItems->map(function (GroupItem $groupItem) use ($request) {
|
||||||
$variant = $featuredVariant->variant;
|
$variant = $groupItem->variant;
|
||||||
$variantResource = (new ProductVariantResource($variant))->toArray($request);
|
$variantResource = (new ProductVariantResource($variant))->toArray($request);
|
||||||
|
|
||||||
if ($this->product_layout === 'row' || $this->product_layout === 'column_with_cart' || $this->product_layout === 'vertical_with_cart') {
|
if ($this->product_layout === 'row' || $this->product_layout === 'column_with_cart' || $this->product_layout === 'vertical_with_cart') {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class FeaturedGroupResource extends JsonResource
|
|||||||
'group_name' => $this->group_name,
|
'group_name' => $this->group_name,
|
||||||
'product_layout' => $this->product_layout,
|
'product_layout' => $this->product_layout,
|
||||||
'group_order' => $this->group_order,
|
'group_order' => $this->group_order,
|
||||||
'featured_variants' => FeaturedVariantResource::collection($this->whenLoaded('featuredVariants')),
|
'featured_variants' => FeaturedVariantResource::collection($this->whenLoaded('groupItems')),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ class TelepagosWebhookService
|
|||||||
$dni = substr($cuit, 2, -1);
|
$dni = substr($cuit, 2, -1);
|
||||||
|
|
||||||
$compra = Purchase::where('tenant_codigo', $tenantCodigo)
|
$compra = Purchase::where('tenant_codigo', $tenantCodigo)
|
||||||
->whereRaw("REPLACE(dni, '.', '') = ?", [$dni])
|
->where('transfer_payer_dni', $dni)
|
||||||
->whereIn('status', [Purchase::STATUS_CREATED, Purchase::STATUS_PENDING_PAYMENT])
|
->whereIn('status', [Purchase::STATUS_CREATED, Purchase::STATUS_PENDING_PAYMENT])
|
||||||
->where('payment_method', 'transfer')
|
->where('payment_method', 'transfer')
|
||||||
->where('total', $amount)
|
->where('total', $amount)
|
||||||
|
|||||||
@@ -68,10 +68,17 @@ class PurchaseController extends Controller
|
|||||||
$method = $request->validated('method');
|
$method = $request->validated('method');
|
||||||
$totalAmount = $compra->calculateCurrentTotalAmount();
|
$totalAmount = $compra->calculateCurrentTotalAmount();
|
||||||
|
|
||||||
$compra->update([
|
$purchaseUpdate = [
|
||||||
'payment_method' => $method,
|
'payment_method' => $method,
|
||||||
|
'status' => Purchase::STATUS_PENDING_PAYMENT,
|
||||||
'total' => $totalAmount,
|
'total' => $totalAmount,
|
||||||
]);
|
];
|
||||||
|
|
||||||
|
if ($method === 'transfer') {
|
||||||
|
$purchaseUpdate['transfer_payer_dni'] = preg_replace('/\D+/', '', (string) $request->validated('transfer_payer_dni'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$compra->update($purchaseUpdate);
|
||||||
|
|
||||||
if ($method === 'transfer') {
|
if ($method === 'transfer') {
|
||||||
$telepagosService = new TelepagosIntegrationService;
|
$telepagosService = new TelepagosIntegrationService;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ use Illuminate\Database\Eloquent\Relations\HasOne;
|
|||||||
'payment_method',
|
'payment_method',
|
||||||
'total',
|
'total',
|
||||||
'dni',
|
'dni',
|
||||||
|
'transfer_payer_dni',
|
||||||
'telefono',
|
'telefono',
|
||||||
'nombre_apellido',
|
'nombre_apellido',
|
||||||
'email',
|
'email',
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ class PaymentIntentRequest extends FormRequest
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'method' => ['required', 'string', Rule::in(['qr', 'transfer'])],
|
'method' => ['required', 'string', Rule::in(['qr', 'transfer'])],
|
||||||
|
'transfer_payer_dni' => [
|
||||||
|
Rule::requiredIf(fn (): bool => $this->input('method') === 'transfer'),
|
||||||
|
'string',
|
||||||
|
'regex:/^\d{7,8}$/',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ class PurchaseResource extends JsonResource
|
|||||||
'status' => $this->status,
|
'status' => $this->status,
|
||||||
'payment_method' => $this->payment_method,
|
'payment_method' => $this->payment_method,
|
||||||
'dni' => $this->dni,
|
'dni' => $this->dni,
|
||||||
|
'transfer_payer_dni' => $this->transfer_payer_dni,
|
||||||
'telefono' => $this->telefono,
|
'telefono' => $this->telefono,
|
||||||
'nombre_apellido' => $this->nombre_apellido,
|
'nombre_apellido' => $this->nombre_apellido,
|
||||||
'email' => $this->email,
|
'email' => $this->email,
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?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('compras', function (Blueprint $table) {
|
||||||
|
$table->string('transfer_payer_dni', 8)->nullable()->after('dni');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('compras', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('transfer_payer_dni');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::rename('featured_variants', 'group_items');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::rename('group_items', 'featured_variants');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -33,6 +33,70 @@ class TelepagosWebhookTest extends TestCase
|
|||||||
Cache::flush();
|
Cache::flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_transfer_payment_intent_requires_a_valid_transfer_payer_dni(): void
|
||||||
|
{
|
||||||
|
$tenant = $this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
||||||
|
$user = User::factory()->create();
|
||||||
|
$variant = $this->createVariantForTenant('sonder', 10, '50.00');
|
||||||
|
$purchase = $this->createPendingTransferPurchase($tenant, $user->id, $variant->id, 1, '12345678');
|
||||||
|
|
||||||
|
$this->actingAs($user, 'sanctum')
|
||||||
|
->postJson("/api/tenants/sonder/compras/{$purchase->id}/payment-intent", [
|
||||||
|
'method' => 'transfer',
|
||||||
|
])
|
||||||
|
->assertUnprocessable()
|
||||||
|
->assertJsonValidationErrors(['transfer_payer_dni']);
|
||||||
|
|
||||||
|
$this->actingAs($user, 'sanctum')
|
||||||
|
->postJson("/api/tenants/sonder/compras/{$purchase->id}/payment-intent", [
|
||||||
|
'method' => 'transfer',
|
||||||
|
'transfer_payer_dni' => '12.345.678',
|
||||||
|
])
|
||||||
|
->assertUnprocessable()
|
||||||
|
->assertJsonValidationErrors(['transfer_payer_dni']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_transfer_payment_intent_persists_transfer_payer_dni_without_replacing_customer_dni(): void
|
||||||
|
{
|
||||||
|
$tenant = $this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
||||||
|
$this->configureTelepagosIntegration($tenant);
|
||||||
|
$user = User::factory()->create();
|
||||||
|
$variant = $this->createVariantForTenant('sonder', 10, '50.00');
|
||||||
|
$purchase = $this->createPendingTransferPurchase($tenant, $user->id, $variant->id, 1, '12345678');
|
||||||
|
$purchase->update(['status' => Purchase::STATUS_CREATED]);
|
||||||
|
|
||||||
|
Http::fake([
|
||||||
|
'https://api.telepagos.com.ar/v2/auth/token' => Http::response([
|
||||||
|
'status' => 'ok',
|
||||||
|
'token' => 'test-token',
|
||||||
|
'expires_at' => now()->addHour()->toIso8601String(),
|
||||||
|
]),
|
||||||
|
'https://api.telepagos.com.ar/v2/account/info' => Http::response([
|
||||||
|
'status' => 'ok',
|
||||||
|
'holder' => 'Telepagos Test',
|
||||||
|
'cvu' => '0000003100000000000001',
|
||||||
|
'alias' => 'telepagos.test',
|
||||||
|
'entity' => 'Telepagos S.A.',
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->actingAs($user, 'sanctum')
|
||||||
|
->postJson("/api/tenants/sonder/compras/{$purchase->id}/payment-intent", [
|
||||||
|
'method' => 'transfer',
|
||||||
|
'transfer_payer_dni' => '23456789',
|
||||||
|
])
|
||||||
|
->assertOk()
|
||||||
|
->assertJsonPath('transfer_data.alias', 'telepagos.test');
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('compras', [
|
||||||
|
'id' => $purchase->id,
|
||||||
|
'dni' => '87654321',
|
||||||
|
'transfer_payer_dni' => '23456789',
|
||||||
|
'payment_method' => 'transfer',
|
||||||
|
'status' => Purchase::STATUS_PENDING_PAYMENT,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function test_transfer_webhook_matches_pending_purchase_by_dni_and_total_amount(): void
|
public function test_transfer_webhook_matches_pending_purchase_by_dni_and_total_amount(): void
|
||||||
{
|
{
|
||||||
$tenant = $this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
$tenant = $this->createTenant('sonder', 'Sonder', 'sonder.com.ar');
|
||||||
@@ -209,7 +273,7 @@ class TelepagosWebhookTest extends TestCase
|
|||||||
|
|
||||||
$purchase = $checkoutService->startCheckout($tenant, $userId, [
|
$purchase = $checkoutService->startCheckout($tenant, $userId, [
|
||||||
'cart_id' => $cart->id,
|
'cart_id' => $cart->id,
|
||||||
'dni' => $dni,
|
'dni' => '87654321',
|
||||||
'telefono' => '+54 9 341 555-4321',
|
'telefono' => '+54 9 341 555-4321',
|
||||||
'nombre_apellido' => 'Juan Perez',
|
'nombre_apellido' => 'Juan Perez',
|
||||||
'email' => 'juan.perez@example.com',
|
'email' => 'juan.perez@example.com',
|
||||||
@@ -217,6 +281,7 @@ class TelepagosWebhookTest extends TestCase
|
|||||||
|
|
||||||
$purchase->update([
|
$purchase->update([
|
||||||
'payment_method' => 'transfer',
|
'payment_method' => 'transfer',
|
||||||
|
'transfer_payer_dni' => $dni,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$checkoutService->completePurchase($purchase);
|
$checkoutService->completePurchase($purchase);
|
||||||
|
|||||||
Reference in New Issue
Block a user