| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788 |
- <?php
- namespace App\Services;
- use App\Models\SparePart;
- use App\Models\SparePartOrder;
- use Illuminate\Support\Collection;
- class SparePartInventoryService
- {
- /**
- * Автоматическое списание запчасти для рекламации
- */
- public function deductForReclamation(
- string $article,
- int $quantity,
- bool $withDocuments,
- int $reclamationId
- ): bool {
- $sparePart = SparePart::where('article', $article)->first();
- if (!$sparePart) {
- return false;
- }
- // Ищем заказ для списания (FIFO - первый созданный)
- $order = SparePartOrder::where('spare_part_id', $sparePart->id)
- ->where('status', SparePartOrder::STATUS_IN_STOCK)
- ->where('with_documents', $withDocuments)
- ->where('remaining_quantity', '>=', $quantity)
- ->orderBy('created_at', 'asc')
- ->first();
- if ($order) {
- // Списываем
- $note = "Автоматическое списание для рекламации: #{$reclamationId}";
- return $order->shipQuantity($quantity, $note, $reclamationId, null);
- } else {
- // Создаём виртуальный заказ с недостачей
- // Статус IN_STOCK чтобы учитывалось в вычисляемых полях!
- SparePartOrder::create([
- 'spare_part_id' => $sparePart->id,
- 'source_text' => "Автоспискание для рекламации #{$reclamationId}",
- 'status' => SparePartOrder::STATUS_IN_STOCK,
- 'ordered_quantity' => 0,
- 'remaining_quantity' => -$quantity,
- 'with_documents' => $withDocuments,
- 'note' => "Недостача, созданная автоматически",
- 'user_id' => auth()->id() ?? 1,
- ]);
- return false;
- }
- }
- /**
- * Получить список запчастей с критическим недостатком (отрицательное количество)
- */
- public function getCriticalShortages(): Collection
- {
- return SparePart::all()->filter(function ($sparePart) {
- return $sparePart->hasCriticalShortage();
- });
- }
- /**
- * Получить список запчастей ниже минимального остатка
- */
- public function getBelowMinStock(): Collection
- {
- return SparePart::all()->filter(function ($sparePart) {
- return $sparePart->isBelowMinStock();
- });
- }
- /**
- * Рассчитать сколько нужно заказать для компенсации недостачи
- */
- public function calculateOrderQuantity(SparePart $sparePart, bool $withDocuments): int
- {
- $quantity = $withDocuments ? $sparePart->quantity_with_docs : $sparePart->quantity_without_docs;
- if ($quantity >= 0) {
- return 0;
- }
- return abs($quantity);
- }
- }
|