with(['items.variant.product', 'items.variant.definitions.productAttribute.attribute']) ->where('tenant_codigo', $tenant->codigo) ->where('user_id', $request->user()->id) ->latest() ->paginateFromRequest() )->response(); } public function store(StorePurchaseRequest $request, Tenant $tenant): JsonResponse { $data = $request->validated(); $items = $data['items']; unset($data['items']); $variants = $this->resolveTenantVariants($tenant, $items); $purchaseItems = $this->buildPurchaseItemsPayload($items, $variants); $purchase = DB::transaction(function () use ($request, $tenant, $data, $purchaseItems): Purchase { /** @var Purchase $purchase */ $purchase = Purchase::query()->create([ ...$data, 'tenant_codigo' => $tenant->codigo, 'user_id' => $request->user()->id, ]); $purchase->items()->createMany($purchaseItems); return $purchase->load(['items.variant.product', 'items.variant.definitions.productAttribute.attribute']); }); return PurchaseResource::make($purchase)->response()->setStatusCode(201); } public function show(Request $request, Tenant $tenant, Purchase $compra): PurchaseResource { $compra = $this->resolveScopedPurchase($tenant, $request->user()->id, $compra); return PurchaseResource::make( $compra->loadMissing(['items.variant.product', 'items.variant.definitions.productAttribute.attribute']) ); } /** * @param array> $items * @return \Illuminate\Support\Collection */ protected function resolveTenantVariants(Tenant $tenant, array $items) { $variantIds = collect($items) ->pluck('producto_variante_id') ->filter() ->map(static fn (mixed $id): int => (int) $id) ->unique() ->values(); $variants = ProductVariant::query() ->with('product') ->whereIn('id', $variantIds) ->whereHas('product', fn ($query) => $query->where('tenant_codigo', $tenant->codigo)) ->get() ->keyBy('id'); if ($variants->count() !== $variantIds->count()) { throw ValidationException::withMessages([ 'items' => 'One or more product variants do not belong to the tenant.', ]); } return $variants; } /** * @param array> $items * @param \Illuminate\Support\Collection $variants * @return array> */ protected function buildPurchaseItemsPayload(array $items, $variants): array { return collect($items) ->map(function (array $item) use ($variants): array { /** @var ProductVariant $variant */ $variant = $variants->get((int) $item['producto_variante_id']); $quantity = (int) $item['cantidad']; $unitPrice = (float) ($variant->product?->precio ?? 0); return [ 'producto_variante_id' => $variant->getKey(), 'cantidad' => $quantity, 'precio_unitario' => $unitPrice, 'discount_total' => null, 'tax_total' => null, 'total' => $unitPrice * $quantity, ]; }) ->all(); } protected function resolveScopedPurchase(Tenant $tenant, int $userId, Purchase $purchase): Purchase { if ($purchase->tenant_codigo !== $tenant->codigo || $purchase->user_id !== $userId) { throw new NotFoundHttpException('Purchase not found for tenant.'); } return $purchase; } }